为什么捕获错误时,promise执行的比setTimeout晚?

我们都知道基于事件循环机制,微任务promise执行是早于setTimeout的,但当这两者发生错误时,setTimeout捕获的比promise更早,以下是代码:

            window.onerror = e => {
                console.log('=====onerror', e)
            }
            window.onunhandledrejection = e => {
                console.log('=====unhandledrejection', e, e.reason)
            }

            function Test() {
                function cacheTest() {
                    new Promise((resolve, reject) => {
                        reject('promiseError')
                    }).catch(e => {
                        console.log('start throw promiseError')
                        throw e
                    })
                    // Promise.reject('promiseError')
                    setTimeout(() => {
                        console.log('start throw setTimeoutError')
                        throw new Error('setTimeoutError'
                    )}, 0)
                    console.log('start throw syncError')
                    throw new Error('syncError')
                }
                return (
                    <div id="test-performance" onClick ={cacheTest}>
                        Test Insight:Cache Exception
                    </div>
                )
            }
            ReactDOM.render( <Test/>, document.getElementById('root'))

执行结果如下:
image.png

但当将setTimeout更改为setTimeout1时一切结果就符合预期了

     setTimeout(() => {
           console.log('start throw setTimeoutError')
           throw new Error('setTimeoutError'
     )}, 1)

执行结果如下:
image.png

这是否时由于setTimeout0存在某种特殊机制导致的?

这个问题,我同步提到了stackoverflow,有该社区的大佬也欢迎围观解答:
https://stackoverflow.com/que...

补充相关官方文档:

阅读 1.5k
2 个回答

啊这?
不是先输出了 start throw promiseError,
然后是 start throw setTimeoutError 吗?

最后的几个不都是你又去使用 throw 抛出的异常吗?
这些异常没有被 catch ,所以会去执行 onerrorunhandledrejection 事件啊。

如果你说的是为什么 .catch 抛出的异常会比 setTimout 抛出的异常输出的晚,主要是你的这个异常抛出没有被捕捉,是通过 unhandledrejection 来捕捉的。如果给这个异常抛出添加上 catch 就会是一致的结果了。

以下是添加好异常捕捉之后的前后对比,希望对你有用。
image.png

那你肯定要问为什么 unhandledrejection 的输出会比 onerror 晚,那我就不清楚了。你得去看 ECMA 制定的规范以及浏览器内核的具体实现了。

EventSource.onerror - Web API 接口参考 | MDN
unhandledrejection - Web API 接口参考 | MDN

主程序执行到 new Promise()处时,立即创建了子线程同时主线程继续往下执行遇到了setTimeout()函数,注意此时你的CUP同时在做两件事,第一件事:创建子线程;第二件事执行setTime([some_stask], 0)函数。第一件事创建完毕以后才能去执行promise里面的回调,因此第一件事本身在节奏上就晚第二件事一步,所以你会先看到setTime先执行。
但是当你把setTime设置成延迟1秒后,主进程这个延迟等待并不影响子线程,主线程暂停期间,子线程已经执行完了,所以你看到的结果又是另外一个顺序。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题