异步编程中的错误处理

前言

在项目中,promise 的应用基本是为了解决异步编程,例如 ajax 请求。而在这个场景下,有个很常见的需求就是捕获请求异常。本篇文章以此为起点,梳理归纳异常错误分类。

一、Promise 中的错误处理

常见错误分类
  1. 编码错误
    此种就是开发过程中,编码有误。
let promise = new Promise(function(resolve, reject) {
    const a = 0;
    a = 10;
});

promise.catch(function(error) {
    console.log('这里打印的错误:',error.message);
});
  1. 主动抛出错误
    业务场景:请求结果的 http 状态值是 4xx、5xx,或者代表业务的 code 值是错误的,需要抛出异常。

在构造函数内部包含一个隐式的 try-catch ,因此内部的错误会被捕捉并被传入 rejection 处理。

let promise = new Promise(function(resolve, reject) {
    throw new Error("出错啦~");
});

promise.catch(function(error) {
    console.log('这里打印的错误:',error.message);
});

等同于以下:

let promise = new Promise(function(resolve, reject) {
    try {
      throw new Error("出错啦~");
    } catch (err) {
      reject(err);
    }
});

promise.catch(function(error) {
    console.log('这里打印的错误:',error.message);
});
  1. 使用 reject 抛出异常比 throw 更好
    通过 throw 抛出的错误在同步任务中能够被 catch ,但如果在异步中, promise 将无法捕获。

运行以下例子可发现,无法捕获到错误。

let promise = new Promise(function(resolve, reject) {
    setTimeout(() => {
        throw new Error("出错啦~");
    },20)
});

promise.catch(function(error) {
    console.log('这里打印的错误:',error.message);     // 无法捕获到错误
});

原因:虽然 promise 的构造函数中有隐含的 try-catch ,但因为setTimeout() 是一个异步任务, 所以它的回调函数执行的时机要比 try-catch 中的 catch 语句晚,导致并没有 regect() 出去错误,所以导致 promise 无法通过 catch 捕获异常。

let promise = new Promise(function(resolve, reject) {
      try {
        setTimeout(() => { // 回调函数执行的晚
          throw new Error("出错啦~");
        },20)
      } catch (err) {
        reject(err);  // 没有执行
      }
});

所以这里推荐使用 reject 替代 throw。如下所示:

let promise = new Promise(function(resolve, reject) {
    setTimeout(() => {
        reject(new Error("出错啦~"));
    },20)
});
  1. 在resolve()后面抛出的错误会被忽略
let promise = new Promise(function(resolve, reject) {
    setTimeout(() => {
    resolve()
        reject(new Error("出错啦~"));
    },20)
});
promise.catch(function(error) {
    console.log('这里打印的错误:',error.message);     // 无法捕获到错误
});
  1. promise 链的异常

运行以下例子:

let promise = Promise.resolve();
promise.then(() => {
 return Promise.reject("first");
}).then(() => {
  console.log("two 没执行");
  return Promise.reject('two');
}).catch((err) => {
  console.log(err); // first
}).then(() => {
  console.log("catch 返回的是一个 promise 对象"); // catch 返回的是一个 promise 对象
   return Promise.reject('three');
}).catch((err) => {
  console.log(err); // three
})
  • reject 抛出错误之后,后续的 then 不再执行,错误被最近的一个 catch 捕获到
  • catch 返回一个 promise
  1. 嵌套 promise 中的 reject

此点源自 [译]深入Promise错误处理

let p2 = new Promise(function(resolve, reject) {
  reject('我是内部的 promise 抛出的错误')
})
let p1 = new Promise(function(resolve, reject) {
  resolve(p2)
})
p1.catch(err => {
   console.log(err)
})

二、Genertor 中的错误处理

  1. 函数内部异常
    在外部通过 try-catch 语句捕获错误。
function *gen() {
  const a = 1;
  yield a = 2; // 故意写错
}
const task = gen();
try {
  task.next();
} catch (e) {
  console.log('捕获到错误了:',e);
}
  1. 通过生成器的 throw() 抛出异常

在生成器函数内部,通过 try-catch 捕获错误。

  • 当异常被捕获后,Generator 函数会继续向下执行,直到遇到下一个 yield 操作并输出 yield 后面表达式的值。
function *gen() {
  try {
    yield console.log(1);
  } catch (e) {
    console.log(e);
  }
  yield console.log(2);
}
const task = gen();
task.next();
task.throw("抛出了异常")

注意 try-catch 的位置,即抛错的位置应该和 try-catch 大致吻合,否则仍旧无法捕获到。

1567373-bc797f5ec7ab5fd9.png
image.png

参考

developer.mozilla Promise.catch()
《Understanding ECMAScript 6》(简体中文版)Promise 与异步编程
《Understanding ECMAScript 6》(简体中文版)迭代器与生成器

扫描二维码关注公众号,回复: 6494009 查看本文章

推荐阅读

Callback Promise Generator Async-Await 和异常处理的演进

转载于:https://www.jianshu.com/p/96453478d9f4

猜你喜欢

转载自blog.csdn.net/weixin_33762130/article/details/91283881