[译]深入Promise错误处理

本文详细探讨了JavaScript中Promise的错误处理机制,包括引发catch的原因、catch的作用范围以及在catch中抛出错误的影响。

原文: https://codeburst.io/promise-error-handling-in-depth-90b0965149c0


在之前的一篇博文中(https://codeburst.io/everything-you-should-know-about-promise-a05a20bf4c53)我们讨论了Promise的基础知识,也简要的提及了应该如何正确处理错误。但其过于基础,并未论述 Promise 使用者会在开发中遇到的一般问题。

所以,让我们稍微花点时间来深挖 Promise 中的错误处理问题,并找出答案。

本文面向那些寻求答案的人,并用 Q 和 A 表示问答。


Q1: 什么会引发 catch?

A1: 当一个 promise 被 reject,就会引发 catch。典型的情况是,调用 reject(reason) 方法。

除此之外,另有3种情况也会引发 reject。


第一种是开发者的失误:

对于程序中的 bug,就应该通过改变编码来避免;程序永远无法正确处置(因为根据定义,存疑的代码注定会崩坏)。
function asyncTask(url) {
  return new Promise((resolve, reject) => {
    a.push(1);

    if (url) {
      return setTimeout(() => {
        resolve({
          id: 1
        });
      }, 500);
    }

    reject({
      error: 'url missing in async task 1'
    });
  });
}

asyncTask('google.com').catch(err => console.log(err)); //ReferenceError: a is not defined复制代码


第二种情况是,明确用 throw 抛出错误也会达到同样的效果:

function asyncTask(url) {
  return new Promise((resolve, reject) => {
    if (url) {
      throw new Error('terminate now');
      return setTimeout(() => {
        resolve({
          id: 1
        });
      }, 500);
    }

    reject({
      error: 'url missing in async task 1'
    });
  });
}

asyncTask('google.com').catch(err => console.log(err)); //Error: terminate now复制代码


最后,嵌套的 promise 也会引发 reject。内层 promise 造成的 reject 状态会冒泡,造成顶层 promise 也 reject:

function asyncTask(url) {
  return new Promise((resolve, reject) => {
    if (url) {
      return setTimeout(() => {
        resolve(asyncTask2());
      }, 500);
    }

    reject({
      error: 'url missing in async task 1'
    });
  });
}

function asyncTask2(url) {
  return new Promise((resolve, reject) => {
    if (url) {
      return resolve({
        id:2
      });
    }

    reject({
      error: 'url missing in async task 2'
    });
  });
}

asyncTask('google.com')
  .catch(err => {
    console.log('failed ', err); // { error: 'url missing in async task 2' }
    return err;
  });复制代码


总而言之,以下3种情况会引发 promise 的 reject:

  • 开发者在 promise 构造器函数中的错误(bug)
  • 明确抛出错误
  • 嵌套 promise 的 reject


Q2: catch 监控什么区域呢?

只需要记住 -- catch 会检查 promise 链上位于它之前的每个地方(then 和其他异步操作);如果它之前还有另一个 catch,则从那个 catch 之后的位置开始。

asyncTask()
  .then()
  .then()
  .then()
  .catch() // 覆盖 asyncTask 和3个 then复制代码
asyncTask()
  .catch() // 只覆盖 asyncTask
  .then()
  .then()
  .catch() // 覆盖了2个 then复制代码

需要注意的就是,和 then 一样, catch 也会返回一个可链式操作的新 promise 对象。


Q3: 可以在 catch 中抛出错误吗?

A3: Yes, you can. 在 catch 中抛出的错误会被下一个 catch 捕获.

asyncTask()
  .then()
  .then()
  .catch(err => {throw new Error('operation failed')})
  .catch(err => console.log(err)) // operation failed复制代码


promise 中的错误处理有可能会很难缠。希望对此不甚明了的人能从本文获益。



-------------------------------------

长按二维码或搜索 fewelife 关注我们哦


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值