javascript - 为什么这里错误不会被抛出?
ringa_lee
ringa_lee 2017-04-11 12:48:52
[JavaScript讨论组]
const promise = new Promise(function (resolve) {
    resolve('ok');
    // setTimeout(function () {
        throw new Error('test');
    // }, 0);
});

promise.then(console.log);

注释去掉之后则可以

ringa_lee
ringa_lee

ringa_lee

全部回复(3)
PHP中文网

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);
})

运行一下上面三段代码,然后你自己稍微再体会一下!!希望对你有帮助。

巴扎黑

我不知道 promise() 过后 Promise 都干了什么,但是我认为 resolve()reject() 是互斥的,一个运行了另一个就不运行了。

另外,如果在 Promise 回调中抛出异常,是会被封装成 reject() 调用的,需要通过 .catch(callback) 来捕捉。

所以,上面,在注释的情况下,已经 resovle() 了,后面的 throw 被封装成的 reject() 调用就被忽略了,所以没有抛出错误。

问题在于把 throw 放在 setTimeout 里之后,估计 reject() 不能把 setTimeout() 的回调封住,所以错误被直接抛出来了,而且不能被 .catch() 到,因为它已经脱离了 Promise 的控制。

迷茫

是不是因为Promise内部的错误不会冒泡的全局,所以需要使用setTimeout方法包装一下?

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号