始终捕获 Promise 中的错误的重要性
P粉590929392
P粉590929392 2024-03-19 21:05:20
0
1
405

我在我的项目中使用 @typescript-eslint/no-floating-promises 规则。如果我写这样的代码,这条规则就会抱怨 -

functionReturningPromise()
    .then(retVal => doSomething(retVal));

它希望我为此 Promise 添加一个 catch 块。如果我想在异常处理块中添加一些逻辑,这对我来说是有意义的。但是,在很多情况下我不需要它。我对抛出的错误很满意。因此,为了抑制此规则引发的错误,我最终这样做了 -

functionReturningPromise()
    .then((retVal) => doSomething(retVal))
    .catch((error) => {
        throw error;
    });
即使我没有像上面那样添加 catch 块,error 仍然会以相同的方式抛出(至少在我的控制台输出中看到它)。因此,我不明白显式指定此 catch 块的意义。我错过了什么吗?如果我添加/不添加 catch 块,抛出 error 的方式真的有区别吗?

P粉590929392
P粉590929392

全部回复(1)
P粉106711425

评论者都很好地回答了您的问题 - 但为了通过示例说明为什么这很重要,请想象以下代码:

Promise.reject();
setTimeout(() => console.log('hello'), 1000);

这段代码看起来相当无害 - 有一个未处理的无操作承诺拒绝,启动后 1 秒程序将记录 'hello'

在浏览器中 - 这正是将会发生的情况 - 浏览器将记录“未捕获的承诺拒绝”错误,但否则会忽略它。

然而,在 NodeJS(从 Node v15 开始)中,未处理的 Promise 拒绝是一个硬错误 - 这意味着进程在检测到错误时将退出!

您可以通过在终端中运行代码来验证这一点(-e 的意思是“评估并运行此代码字符串”)

$ node -e "Promise.reject(); setTimeout(() => console.log('hello'), 1000)"
node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "undefined".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Node.js v18.12.1

您可以看到 'hello' 永远不会被打印,因为进程在 1 秒之前终止!

要验证事情是否按预期工作,您可以将 .reject 更改为 .resolve

$ node -e "Promise.resolve(); setTimeout(() => console.log('hello'), 1000)"
hello

因此,如果您正在使用任何 LTS 支持的版本编写 NodeJS 应用程序,那么您绝对应该处理错误,否则您将面临意外崩溃的风险。

如果您的代码仅在浏览器中运行,那么您可能想知道是否应该处理失败 - 毕竟您的用户没有查看控制台,因此他们不会知道发生了任何不好的事情,所以谁在乎呢?从“仅代码”的角度来看,您是正确的 - 但是,当出现问题时,您的用户希望从他们的应用程序中获得反馈。

想象一下以下场景 - 您的 Promise 跟踪 API 调用的结果,该调用提交用户在您的应用程序中输入的一些数据。如果该 API 调用由于某种原因失败,那么您的应用程序应该做出适当的响应并告诉用户出了问题。

处理它的替代方法可能意味着您的应用程序显示无限加载旋转器,或者用户认为他们的数据已成功提交,但实际上并未成功。无论哪种方式 - 这是一个非常糟糕且破碎的用户体验!

最后做一些像 .catch(e => { throw e }) 这样的事情,你实际上并没有处理错误。当然,这段代码会使 linter 保持沉默 - 但您所做的只是创建一个新的、被拒绝的承诺,该承诺将记录到控制台。相反,您应该以某种方式将错误连接到应用程序的 UI,例如像 .catch(e => {alert(e); throw e }) 这样简单的东西会更好。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板