问:如何处理Promise抛出的错误异常 答:使用catch方法以链式调用的方式进行捕获
问:async/await的异常处理呢? 答:使用try...catch
问:那Promise可以使用try...catch捕获到吗? 答:不可以
问:那为什么Promise不可以try...catch,但是async/await可以呢? 答:async/await本质也是基于promise和generator实现的语法糖,具体原理机制不清楚,猜测是async/await内部throw了error,才能通过try-catch捕获到吧。
面试官:emm,自己回去可以看看。。。
以上面试对话,最后一个问题,我也没有太深的研究过。面试后找了些资料,这里记录下 我觉得自己答的确实没有到点上,原因是当时没有认识到以下的知识点:
首先,要明白一点,异常错误是由层级的,比如在某个函数内出现的异常,如果你没有catch到,那么错误会一直沿着调用栈往上一层throw,如果上一层也没有catch到,那么继续往上报错,最终到达全局,变成了全局错误。
第二点,错误会引发什么问题?会导致程序以错误终止,导致程序的崩溃。也就是说你的代码程序到此为止了,后面的代码也不会再执行了,devtool会出现红色错误提示。
第三点,错误还有很多类型,promise只是其中一种,这里不发散开了, 重点讨论promise类型的。这一块可以去jartto.wang/2018/11/20/… 了解或者网上查下,比较容易找得到。
错误到导致程序崩溃,不再运行,比较常见,相信基本都遇到过。 捕获到异常的神奇之处就在于:能让程序继续执行,而不会中断。
// 执行流:
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function(error) {
alert("The error is handled, continue normally");
}).then(() => alert("Next successful handler runs"));
上面代码promise抛出的错误被catch住了,所以继续执行了then中的回调函数。如果去掉了catch, 那么then中的函数也不会继续执行了。自己试了,promise中的错误,会阻塞then中的执行,但是不会影响promise外面的其他代码。
上面讲了关于异常的机制和处理方式,下面重点看promise的错误处理。
隐式的try...catch
promise 的执行者(executor)和 promise 的处理程序周围有一个隐式的 try..catch。如果发生异常,它就会被捕获,并被视为 rejection 进行处理。
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(alert);
// Error: Whoops!
等同于:
new Promise((resolve, reject) => {
reject(new Error("Whoops!"));
}).catch(alert); // Error: Whoops!
在 executor 周围的“隐式 try..catch”自动捕获了 error,并将其变为 rejected promise。JavaScript 引擎会跟踪此类 rejection,在这种情况下会生成一个全局的 error。如果你运行上面这个代码,你可以在控制台中看到。
在浏览器中,我们可以使用 unhandledrejection 事件来捕获这类 error:
window.addEventListener('unhandledrejection', function(event) {
// 这个事件对象有两个特殊的属性:
alert(event.promise); // [object Promise] —— 生成该全局 error 的 promise
alert(event.reason); // Error: Whoops! —— 未处理的 error 对象
});
new Promise(function() {
throw new Error("Whoops!");
}); // 没有用来处理 error 的 catch
补充:catch无法捕获异步的error
new Promise(function(resolve, reject) {
setTimeout(() => {
throw new Error("Whoops!");
}, 1000);
}).catch(alert);
一秒后,错误爆出了。我的理解是:setTimeout回调中的函数是全局作用域执行,在当前promise执行栈中看不到,因为已经上升到全局作用域了。应该用window.onunhandledrejection来监听处理
window.addEventListener('unhandledrejection', (e) => {
console.log(e, 'catch you')
});
new Promise((res, rej) => {
setTimeout(() => {
rej("Whoops!");
}, 1000)
})
有不对之处,欢迎大神指正。 下回继续更新