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);
注释去掉之后则可以
我不知道 promise()
过后 Promise
都干了什么,但是我认为 resolve()
和 reject()
是互斥的,一个运行了另一个就不运行了。
另外,如果在 Promise 回调中抛出异常,是会被封装成 reject()
调用的,需要通过 .catch(callback)
来捕捉。
所以,上面,在注释的情况下,已经 resovle()
了,后面的 throw
被封装成的 reject()
调用就被忽略了,所以没有抛出错误。
问题在于把 throw
放在 setTimeout
里之后,估计 reject()
不能把 setTimeout()
的回调封住,所以错误被直接抛出来了,而且不能被 .catch()
到,因为它已经脱离了 Promise 的控制。
1.首先你要明白一个promise
有三种状态,分别是pending
, resolved
(alias: fulfilled) 和 rejected
。 而且一旦状态改变,就不会再变,任何时候都可以得到这个结果。状态改变只有两种可能:从pending变为resolved和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。
2.当你注释掉你的setTimeout之后代码就变成了
const promise = new Promise(function (resolve) {
resolve('ok');
// setTimeout(function () {
throw new Error('test');
// }, 0);
});
上面的resolve('ok')
已经将Promise的状态变成了resolved
, 你再throw error
是不会被捕获的。
3.为什么加了setTimeout
之后就可以了捕获了,因为你加了setTimeout之后, 是指定到下一轮“事件循环”再抛出错误,将冒泡到最外层,成了未捕获的错误。因为此时,Promise已经resolved了,完成了自己的任务,所以这个错误是在Promise函数体外抛出的。 你这个时候抛错误出来会被进程捕获并丢出来的。
Supplement from @haidao17 :
不仅是 rejected 或者是 resolved, 就算 Promise 仍处于 pendding 状态,只要是在下一次(next tick)事件轮询中才触发的错误,都不会被 Promise 捕捉到,除非直接使用 reject()
4.解释并改造你的三段代码说明一下
4-1. 下面例子中throw Error
会被promise的catch方法捕获!
const promise = new Promise(function (resolve) {
throw new Error('test');
resolve('ok');
});
// catch会捕获上面的error
promise.then(console.log).catch(console.error);
4-2. 下面例子中throw Error
被忽略!!!!等价于没有抛出错误
const promise = new Promise(function (resolve) {
resolve('ok');
throw new Error('test');
});
promise.then(console.log).catch(console.error);
4-1和4-2说明了Promise的状态一旦改变就是永久的改变,一直保持这个状态,之后是无法再改变的。
4-3. 下面例子中throw Error
会被process捕获!
const promise = new Promise(function (resolve) {
// throw new Error('test');
resolve('ok');
setTimeout(function () {
throw new Error('test');
}, 0);
});
promise.then(console.log).catch(console.error);
// setTimeout里面的error在这里被捕获
process.on('uncaughtException', (err) => {
console.error('got uncaughtExpection=', err);
})
运行一下上面三段代码,然后你自己稍微再体会一下!!希望对你有帮助。
10 回答11.1k 阅读
6 回答3k 阅读
5 回答4.8k 阅读✓ 已解决
4 回答3.1k 阅读✓ 已解决
2 回答2.6k 阅读✓ 已解决
4 回答2.4k 阅读✓ 已解决
3 回答2.3k 阅读✓ 已解决
终于回到学校了...
题主所说的情况:
问题:不能抛出异常.
接下来我们多个情况分析并尝试解释下.
首先给大家抛个源码地址吧
传送门:https://github.com/then/promi...
注释掉setTimeout的情况下,console.log出"ok"
Promise函数中,doResolve其实与then函数中处理相似,都具有2点的特征,也就是一次性,所以在调用了resolve("ok")后,状态和值已经固定,并传给了then()
then函数的问题,我们看看then函数是怎样的
promise2 = promise1.then(onFulfilled, onRejected)
,传入onFulfilled,onRejected两个函数,返回一个promise对象.具体可以看我博文,现在我把题主传入函数对应的情况拿出来.我们可以看出promise传递给then,then只接受了onFulfilled函数,所以console中出现了"ok"
注释掉resolve("ok")和setTimeout,console无任何信息
在
new Promise(fn)
中,为了让promise正常生成,在内部进行了错误的捕获,具体函数是这样的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"并抛出异常的现象
其实这里我也不是很清楚,希望有人做个补充