目录

JS 中 try-catch 能不能捕获到异步中抛出的错误?

结论

  • 普通函数中的异步抛出错误 try-catch 无法捕获到
  • async 中,用 await 关键字标识的异步可以被捕获到

例子

1、定时器异步中的异常无法被捕获

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const init = () => {
  try {
    setTimeout(() => {
      throw "error: fail";
    }, 500);
  } catch (e) {
    console.log(e);
  }
};

init();

2、promise 异步中异常无法被捕获

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const task = () => {
  return new Promise((res, rej) => {
    setTimeout(() => {
      rej("error: task fail");
    }, 500);
  });
};

const init = () => {
  try {
    task().then((res) => {
      console.log("success:", res);
    });
  } catch (e) {
    console.log(e);
  }
};

init();

3、async 函数中,promise 异步中异常无法被捕获

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const task = () => {
  return new Promise((res, rej) => {
    setTimeout(() => {
      rej("error: task fail");
    }, 500);
  });
};

const init = async () => {
  try {
    task().then((res) => {
      console.log("success:", res);
    });
  } catch (e) {
    console.log(e);
  }
};

init();

4、async 函数中,await 标记的函数可以被捕获

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const task = () => {
  return new Promise((res, rej) => {
    setTimeout(() => {
      rej("error: task fail");
    }, 500);
  });
};

const init = async () => {
  try {
    const res = await task();
    console.log("success:", res);
  } catch (e) {
    console.log(e);
  }
};

init();

为什么 async 函数中,await 标记的函数可以被捕获,它是如何实现的?

众所周知 asyncawait 是 Generator 函数的语法糖。

所以问题就转换为 Generator 函数 如何捕获异步异常,这里的关键是 co 函数,参考下面的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const task = () => {
  return new Promise((res, rej) => {
    setTimeout(() => {
      rej("error: task fail");
    }, 500);
  });
};

const init = () => {
  return co(function* () {
    try {
      const res = yield task();
      console.log("success:", res);
    } catch (e) {
      console.log(e);
    }
  });
};

function co(genF) {
  return new Promise(function (resolve, reject) {
    var gen = genF();
    function step(nextF) {
      try {
        var next = nextF();
      } catch (e) {
        return reject(e);
      }
      if (next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(
        function (v) {
          step(function () {
            return gen.next(v);
          });
        },
        function (e) {
          step(function () {
            return gen.throw(e);
          });
        }
      );
    }
    step(function () {
      return gen.next(undefined);
    });
  });
}

init();

上面的 co 是简单实现, 完整的实现 点这里

参考链接