当前位置:   article > 正文

对 JavaScript 中的 try-catch 能否捕获异步错误的探究_js try catch 异步

js try catch 异步

对 JavaScript 中的 try-catch 能否捕获异步错误的探究


try-catch 是用来捕获同步错误的,而以下代码却是可以捕捉到异步错误的:

async function run() {
    try {
        let a = await Promise.reject(new Error("Oops!"));//【0】
    } catch (error) {
        console.log(error.message); // "Oops!"
    }
    let b = await Promise.resolve("[1]")
}
run();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

如果上述【0】处去掉 await,就捕捉不到错误。

因为 async/await 本质上就是一个语法糖,所以要知道上述代码脱去语法糖表皮之后的样子。首先准备好基础知识,我依次看了迭代器、生成器、async/await 的实现原理。

babel 在线转换 是一个 ES 版本在线转换网站。我记得 async/await 是 ES8 的内容。我将上述代码转换成 ES6 版本的代码,结果如下(至于为什么要转换成 ES6,对于我个人来说,到 ES6 这个层面目前就已经够了):

/*原本的代码:
run();

async function run() {
    try {
        let a = await Promise.reject(new Error("Oops!"));
    } catch (error) {
        console.log(error.message); // "Oops!"
    }
    let b = await Promise.resolve("[1]")
}
*/
"use strict";


function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);//【2】
    console.log("here", info);
    var value = info.value;
  } catch (error) { //【3】
    reject(error);
    return;
  }
  if (info.done) {//生成器到头了
    resolve(value);
  }
  else {
    Promise.resolve(value).then(_next, _throw); /*【0】注意:这里假设 value 为
    一个 rejected 状态的 Promise 实例就会执行 _throw 方法,于是【1】处的语句
    执行,asyncGeneratorStep 入栈;执行到【2】时,gen[throw](arg) 的 作用是
    抛出一个错误(如果这个错误没有被生成器内部处理,才会冒出来,被【3】处
    的 catch 捕捉到。可是显然【4】处有 catch,这里位于生成器内部,所以错误就
    被【4】合理地处理了,【3】是抓不到的)。
    如果生成器内部没有去 catch,那就会被【3】抓到,然后 reject 了,也即所谓的
    异步函数返回了 rejected 的 Promise 实例。*/
  }
}
function _asyncToGenerator(fn) {
  return function () {
    var self = this, args = arguments;
    return new Promise(function (resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);//【1】
      }
      _next(undefined);
    });
  };
}
function _run() {
  _run = _asyncToGenerator(function* () {
    try {
      let a = yield Promise.reject("[0]");//这里,await变成了yield
    } catch (error) {//【4】
      console.log(error.message); // "Oops!"
    }
    let b = yield Promise.resolve("[1]")
  });/*这个函数的参数应该是babel由原来的run转换过来的,目前看来只是简单地
  将"await"替换成了"yield"。*/
  return _run.apply(this, arguments);
}
function run() {
  return _run.apply(this, arguments);
}
run();
  • 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
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

原程序中 try-catch 为什么能够捕捉到异步错误的原因,我都写在了上述程序的注释中了。还是建议先去学一下迭代器、生成器、async/await 的实现原理,之后再回来仔细看一遍这个程序。

总之,try-catch 实质上并没有捕捉到那个异步错误,异步错误还是只能异步地捕捉。只不过 Promise 的 onRejected 处理程序借助生成器原生的 throw() 方法将错误丢到了生成器内部,于是才被生成器内部的 try-catch 捕捉到了。

注:本文为原创文章,转载请标明出处

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/252885
推荐阅读
相关标签
  

闽ICP备14008679号