有关此代码段的执行顺序的问题

Joj*_*oji 11 javascript event-loop

因此,最近我一直在阅读有关Javascript承诺的教程。

这是一个示例,用于解释宏任务队列(即事件循环)和微任务队列。

let promise = Promise.reject(new Error("Promise Failed!"));
promise.catch(err => alert('caught'));

// no error, all quiet
window.addEventListener('unhandledrejection', event => alert(event.reason));
Run Code Online (Sandbox Code Playgroud)

它说,因为promise.catch捕获错误,所以最后一行,所以事件处理程序永远不会运行。我能理解 但是随后他稍微调整了这个示例。

let promise = Promise.reject(new Error("Promise Failed!"));
setTimeout(() => promise.catch(err => alert('caught')));

// Error: Promise Failed!
window.addEventListener('unhandledrejection', event => alert(event.reason));
Run Code Online (Sandbox Code Playgroud)

这一次,他说,事件处理程序会首先运行,并捕获错误并经过这个promise.catch最终捕获错误。

对于第二个示例,我不了解的是,为什么事件处理程序在promise.catch?之前运行?

我的理解是

  1. 第一行,我们首先遇到一个承诺,然后将其放在微任务队列中。
  2. 第二行,我们有一个setTimeout,将其放在宏任务队列中,
  3. 第三行,我们有一个事件处理程序,并将该处理程序放在宏任务队列上等待被触发

然后,因为微任务比宏任务具有更高的优先级。我们首先兑现诺言。之后,我们将宏任务队列中的第一个任务出队setTimeout。因此,根据我的理解,该错误应由内部函数捕获setTimeout

请纠正我。

Jon*_*lms 3

您对步骤 3) 的理解是错误的。处理程序将同步添加。然后微任务队列开始运行,并且 Promise 被拒绝。由于尚未.catch添加处理程序,因此会抛出未处理的拒绝。

我认为您在添加回调的时间执行回调的时间之间进行了混合。考虑这种情况:

  (new Promise).then(function callback() { });
Run Code Online (Sandbox Code Playgroud)

回调将同步添加,但永远不会被调用,因为承诺永远不会解析。在这种情况下:

  Promise.resolve().then(function callback() { });
Run Code Online (Sandbox Code Playgroud)

回调再次同步添加,但承诺解析发生在微任务中,因此回调将稍后执行。