赞
踩
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();
如果上述【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();
原程序中 try-catch 为什么能够捕捉到异步错误的原因,我都写在了上述程序的注释中了。还是建议先去学一下迭代器、生成器、async/await 的实现原理,之后再回来仔细看一遍这个程序。
总之,try-catch 实质上并没有捕捉到那个异步错误,异步错误还是只能异步地捕捉。只不过 Promise 的 onRejected 处理程序借助生成器原生的 throw() 方法将错误丢到了生成器内部,于是才被生成器内部的 try-catch 捕捉到了。
注:本文为原创文章,转载请标明出处
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。