我对Timer函数,微任务和事件侦听器的执行顺序有疑问:
let promise = Promise.reject("Err@!");
setTimeout(() => {
promise.catch(er => console.log(er, "Caught !")); // (1)
});
window.addEventListener('unhandledrejection', event => console.log("Unhandled Rejection !", event.reason)); // (2)
// Output
// >> Unhandled Rejection ! Err@!
// >> Err@! Caught !
[在此情况下,被拒绝的承诺在setTimeout内部被.catch()捕获之前被Unhandled Rejection事件捕获,其原因是,
如果未处理承诺错误,则会发生“未处理的拒绝”微任务队列的结尾(https://javascript.info/microtask-queue#unhandled-rejection)
现在考虑另一种情况:
let promise = Promise.reject("Err@!");
setTimeout(() => { // (1) ,gets called first
setTimeout(function () { // (3) , gets called at last , (after (2))
promise.catch(er => console.log("caught ", er ))
})
});
setTimeout(function () { // (2) , gets called after (1)
window.addEventListener('unhandledrejection', event => console.log("Unhandled Rejection !", event.reason));
})
// Output
//>> caught Err@!
在这种情况下,即使在第二setTimeout中,即使在第二个setTimeout中,promise也会被捕获处理程序捕获在嵌套setTimeout中,并且微任务队列为空,并且拒绝的Promise仍不能由窗口事件侦听器处理...
为什么?
到诺言被拒绝(没有被处理)时,unhandledrejection处理程序尚未附加,因此它不处理该案件。您可以随时随地附加.catch
和.then
处理程序,如果Promise已被解决/拒绝,它们将立即执行(在微任务中)。
// first example
1) synchronous execution
- promise rejected
- timeout set
- unhandledrejection event handler attached
2) microtasks
- promise rejects
3) macrotask
- timeout triggers
-> .catch handler gets attached
4) microtasks
.catch gets executed
// second example
1) synchronous execution
- timers get attached
- promise rejects
2) microtasks
- promise rejected
3) macrotasks
- timer 1 done
- timer 3 started
- timer 2 done
- unhandledrejection handler added