前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >有了"承诺"之后,没完成,需要处理

有了"承诺"之后,没完成,需要处理

作者头像
公众号---人生代码
发布2021-03-16 15:15:00
发布2021-03-16 15:15:00
1.3K00
代码可运行
举报
文章被收录于专栏:人生代码人生代码
运行总次数:0
代码可运行

Promise 在错误处理方面非常出色。当 promise 拒绝时,控件跳转到最近的拒绝处理程序。这在实践中很方便。

例如,下面的代码中获取的URL是错误的(没有这样的站点),.catch处理错误:

代码语言:javascript
代码运行次数:0
复制
fetch('https://no-such-server.blabla') // rejects
  .then(response => response.json())
  .catch(err => alert(err)) // TypeError: failed to fetch (the text may vary)

如您所见,.catch不一定是即时的。它可能出现在一个或几个 .then。

或者,可能站点一切正常,但响应不是有效的JSON。捕获所有错误的最简单方法是将.catch添加到chain的末尾:

代码语言:javascript
代码运行次数:0
复制
fetch('/article/promise-chaining/user.json')
  .then(response => response.json())
  .then(user => fetch(`https://api.github.com/users/${user.name}`))
  .then(response => response.json())
  .then(githubUser => new Promise((resolve, reject) => {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => {
      img.remove();
      resolve(githubUser);
    }, 3000);
  }))
  .catch(error => alert(error.message));

通常,这种 .catch根本不会触发。但是,如果上面的任何一个 Promise 被拒绝(网络问题或无效的json或其他什么),那么它就会捕获它。

隐式 try catch

Promise 执行程序和 Promise 处理程序的代码有一个“不可见的 try..catch。如果发生了异常,它会被捕获并作为拒绝处理。

例如,以下代码:

代码语言:javascript
代码运行次数:0
复制
new Promise((resolve, reject) => {
  throw new Error("Whoops!");
}).catch(alert); // Error: Whoops!

工作原理完全一样:

代码语言:javascript
代码运行次数:0
复制
new Promise((resolve, reject) => {
  reject(new Error("Whoops!"));
}).catch(alert); // Error: Whoops!

“看不见的try..catch,执行程序会自动捕获错误并将其转换为被拒绝的Promise。

这不仅发生在executor函数中,也发生在其处理程序中。如果我们抛出一个.then处理程序,这意味着一个被拒绝的承诺,因此控件跳转到最近的错误处理程序。

这里有一个例子:

代码语言:javascript
代码运行次数:0
复制
new Promise((resolve, reject) => {
  resolve("ok");
}).then((result) => {
  throw new Error("Whoops!"); // rejects the promise
}).catch(alert); // Error: Whoops!

所有错误都会发生这种情况,而不仅仅是由throw语句引起的错误。例如,一个编程错误:

代码语言:javascript
代码运行次数:0
复制
new Promise((resolve, reject) => {
  resolve("ok");
}).then((result) => {
  blabla(); // no such function
}).catch(alert); // ReferenceError: blabla is not defined

最后的.catch不仅能捕获显式的拒绝,还能捕获上述处理程序中的意外错误。

Rethrowing

正如我们已经注意到的,.catch在链的末端类似于try..catch。我们可以有任意多的.then处理程序,然后在末尾使用一个.catch来处理所有处理程序中的错误。

在定期的尝试中…我们可以分析错误,如果不能处理,可能会重新抛出错误。同样的事情也可能发生在承诺上。

如果我们在.catch中抛出,那么控件将转到下一个最近的错误处理程序。如果我们处理错误并正常完成,那么它会继续到下一个成功的。then handler。

在下面的例子中,.catch成功地处理了错误:

代码语言:javascript
代码运行次数:0
复制
// the execution: catch -> then
new Promise((resolve, reject) => {

  throw new Error("Whoops!");

}).catch(function(error) {

  alert("The error is handled, continue normally");

}).then(() => alert("Next successful handler runs"));

在这里,.catch块正常完成。因此,调用下一个成功的.then处理程序。

在下面的例子中,我们将看到.catch的另一种情况。处理程序(*)捕获了错误,但无法处理它(例如,它只知道如何处理URIError),所以它再次抛出它:

代码语言:javascript
代码运行次数:0
复制
// the execution: catch -> catch
new Promise((resolve, reject) => {

  throw new Error("Whoops!");

}).catch(function(error) { // (*)

  if (error instanceof URIError) {
    // handle it
  } else {
    alert("Can't handle such error");

    throw error; // throwing this or another error jumps to the next catch
  }

}).then(function() {
  /* doesn't run here */
}).catch(error => { // (**)

  alert(`The unknown error has occurred: ${error}`);
  // don't return anything => execution goes the normal way

});

执行过程从第一个.catch(*)跳转到下一个。catch(**)。

Unhandled rejections

当错误没有被处理时会发生什么?例如,我们忘记将.catch添加到链的末尾,就像这样:

代码语言:javascript
代码运行次数:0
复制
new Promise(function() {
  noSuchFunction(); // Error here (no such function)
})
  .then(() => {
    // successful promise handlers, one or more
  }); // without .catch at the end!

在出现错误的情况下,承诺被拒绝,执行应该跳转到最近的拒绝处理程序。但是没有。所以错误被“卡住”了。没有代码来处理它。

在实践中,就像代码中的常规未处理错误一样,这意味着某些东西出现了严重的错误。

如果出现了常规错误,但是try..catch没有捕捉到,会发生什么情况?脚本在控制台中结束,并显示一条消息。类似的事情也会发生在未经处理的拒绝承诺上。

JavaScript引擎会跟踪这种拒绝并在这种情况下生成一个全局错误。如果运行上面的示例,就可以在控制台中看到它。

在浏览器中,我们可以使用unhandledrejection事件来捕获这样的错误:

代码语言:javascript
代码运行次数:0
复制
window.addEventListener('unhandledrejection', function(event) {
  // the event object has two special properties:
  alert(event.promise); // [object Promise] - the promise that generated the error
  alert(event.reason); // Error: Whoops! - the unhandled error object
});

new Promise(function() {
  throw new Error("Whoops!");
}); // no catch to handle the error

事件是HTML标准的一部分。

如果发生了错误,但是没有.catch, unhandledrejection处理程序就会触发,并获取带有错误信息的事件对象,因此我们可以做一些事情。

通常这种错误是不可恢复的,所以我们最好的解决方法是通知用户这个问题,并可能向服务器报告这个事件。

在非浏览器环境中,如Node。还有其他方法可以跟踪未处理的错误。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 隐式 try catch
  • Rethrowing
  • Unhandled rejections
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档