javascript - 为什么这里错误不会被抛出?
问题描述
const promise = new Promise(function (resolve) {
resolve('ok');
// setTimeout(function () {
throw new Error('test');
// }, 0);
});
promise.then(console.log);
注释去掉之后则可以
终于回到学校了...
题主所说的情况:
const promise = new Promise(function (resolve) {
resolve('ok');
// setTimeout(function () {
throw new Error('test');
// }, 0);
});
promise.then(console.log);
问题:不能抛出异常.
接下来我们多个情况分析并尝试解释下.
首先给大家抛个源码地址吧
传送门:https://github.com/then/promi...
function Promise(fn) {
if (typeof this !== 'object') {
throw new TypeError('Promises must be constructed via new');
}
if (typeof fn !== 'function') {
throw new TypeError('Promise constructor\'s argument is not a function');
}
this._deferredState = 0;
this._state = 0;
this._value = null;
this._deferreds = null;
if (fn === noop) return;
doResolve(fn, this);
}
//其中doResolve()中对抛出错误进行了处理并调用了相应resolve()/reject()函数来修改自身的状态和值/拒因
注释掉setTimeout的情况下,console.log出"ok"
Promise函数中,doResolve其实与then函数中处理相似,都具有2点的特征,也就是一次性,所以在调用了resolve("ok")后,状态和值已经固定,并传给了then()
then函数的问题,我们看看then函数是怎样的
promise2 = promise1.then(onFulfilled, onRejected)
,传入onFulfilled,onRejected两个函数,返回一个promise对象.具体可以看我博文,现在我把题主传入函数对应的情况拿出来.
如果onFulfilled不是函数且promise1状态为fulfilled,则promise2状态为fulfilled且值与promise1的值相同
如果onRejected不是函数且promise1状态为rejected,那么promise2状态必须为rejected且与promise1的reason拒因相同.
onFulfilled和onRejected函数只能在promise状态为fulfilled/rejected时调用一次
我们可以看出promise传递给then,then只接受了onFulfilled函数,所以console中出现了"ok"
注释掉resolve("ok")和setTimeout,console无任何信息
在new Promise(fn)
中,为了让promise正常生成,在内部进行了错误的捕获,具体函数是这样的
function tryCallTwo(fn, a, b) {
try {
fn(a, b);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
Promise把传入的fn函数进行了错误的捕获,并且返回IS_ERROR来表示出现了异常,在这个时候异常已经被捕获并处理了,然后根据这个异常我们的promise的状态也由pending->rejected,并且拥有了拒因 异常ex.
这个promise传递给了then函数,然而,我们的then函数中onRejected是undefined的,所以这个then函数直接返回了新的rejected并带有拒因 异常ex 的promise对象(then必须返回一个promise对象.)以其后续处理.
所以console中没有任何信息生成
不注释任何代码,直接执行,console中出现"ok"并接着抛出异常
出现"ok"的原因我们说清楚了,然后抛出异常就是因为setTimeout 0的作用了.
众所周知,JavaScript于浏览器端是单线程执行的,我们的任务是一个队列(event loop),所谓的延时,计时器,触发回调是都是基于计时器的,所谓触发执行其实都是立即排队而已.当setTimeout设置时间为0,也代表的是立即插入队列,不是立即执行,也不保证执行时间,所以这样setTimeout(fn,0)其实表示的不是立即执行,而是你排队吧,类似于将队伍里第一个人扔到队尾去了.
所以异常其实是在执行完了promise构建后被抛出的,所以,就出现了console中出现"ok"并抛出异常的现象
其实这里我也不是很清楚,希望有人做个补充
这篇关于javascript - 为什么这里错误不会被抛出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!