事件循环中微任务和宏任务队列的区别

2025-06-07

事件循环中微任务和宏任务队列的区别

什么是事件循环?

事件循环是一种允许 JavaScript 在单线程环境中执行异步代码的机制。它通过不断检查两个队列来工作:微任务队列和宏任务队列。这两个队列存储了等待执行的异步操作的回调。



setTimeout(function() {
  console.log("Hello after 3 seconds");
}, 3000);



Enter fullscreen mode Exit fullscreen mode

本例中的回调函数将在 3 秒后执行,但不会立即执行。它会被放入宏任务队列中,等待轮到自己执行。

微任务和宏任务队列有什么区别?

微任务和宏任务队列的主要区别在于它们的优先级。事件循环始终赋予微任务队列更高的优先级,并会在处理完微任务队列中的所有回调后,再处理宏任务队列。

微任务队列包含被认为更紧急或更重要的操作的回调,例如承诺和变异观察者 API。

宏任务队列包含不太紧急的操作的回调,例如计时器、I/O 事件和用户界面事件。



console.log("Start");

setTimeout(function() {
  console.log("Timeout");
}, 0);

Promise.resolve().then(function() {
  console.log("Promise"); // microTask!
});

console.log("End");



Enter fullscreen mode Exit fullscreen mode

你觉得这段代码的输出会是什么?你可能认为是:

Start -> Timeout -> Promise -> End

但实际上,它会是:

Start -> End -> Promise -> Timeout

让我们一步一步解码:

因为的回调setTimeout是放在宏任务队列中的,而的回调Promise.resolve是放在微任务队列中的。

  • 事件循环将首先执行同步代码(console.log("Start") 和 console.log("End"))
  • 然后它将检查微任务队列并执行那里的所有回调(console.log(“Promise”))
  • 然后它将检查宏任务队列并在那里执行一个回调(console.log(“Timeout”))。

为什么了解差异很重要?

了解微任务和宏任务队列之间的区别可以帮助你用 JavaScript 编写更好的异步代码。它可以帮助你避免一些常见的错误,例如:

  • 通过创建过多的微任务或长时间运行的微任务来阻塞事件循环。这可能会导致性能问题并延迟其他重要任务。
  • 依赖不同类型任务的执行顺序,可能会造成竞争条件或意外结果。例如,如果您使用 setTimeout 在 Promise 之后安排某些代码,则无法保证该 Promise 会在超时之前完成解析。
  • 例如,如果您使用延迟 0 毫秒的 setTimeout 来推迟某些代码的执行,则可能会错过其间发生的一些事件。

为了避免这些错误,请遵循一些最佳做法,例如:

  • 尽可能使用 Promise 或 async/await 代替回调。Promise 比嵌套回调更易于阅读、编写和调试。它们还能让你更轻松地处理错误。
  • 使用queueMicrotask代替 setTimeout,并设置极小的延迟。这些方法比 setTimeout 更可靠、更高效,因为它们会立即调度微任务,且没有任何延迟。

结论

图片描述

希望本文能帮助您理解事件循环中微任务和宏任务队列的区别。您可以查看我关于JS 中的DebounceThrottling 的通俗易懂的文章🚀

文章来源:https://dev.to/jeetvora331/difference- Between-microtask-and-macrotask-queue-in-the-event-loop-4i4i
PREV
JavaScript 中节流最简单的解释✨🚀
NEXT
TailwindCSS 初学者指南!