事件循环中微任务和宏任务队列的区别
什么是事件循环?
事件循环是一种允许 JavaScript 在单线程环境中执行异步代码的机制。它通过不断检查两个队列来工作:微任务队列和宏任务队列。这两个队列存储了等待执行的异步操作的回调。
setTimeout(function() {
console.log("Hello after 3 seconds");
}, 3000);
本例中的回调函数将在 3 秒后执行,但不会立即执行。它会被放入宏任务队列中,等待轮到自己执行。
微任务和宏任务队列有什么区别?
微任务和宏任务队列的主要区别在于它们的优先级。事件循环始终赋予微任务队列更高的优先级,并会在处理完微任务队列中的所有回调后,再处理宏任务队列。
微任务队列包含被认为更紧急或更重要的操作的回调,例如承诺和变异观察者 API。
宏任务队列包含不太紧急的操作的回调,例如计时器、I/O 事件和用户界面事件。
console.log("Start");
setTimeout(function() {
console.log("Timeout");
}, 0);
Promise.resolve().then(function() {
console.log("Promise"); // microTask!
});
console.log("End");
你觉得这段代码的输出会是什么?你可能认为是:
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 中的Debounce和Throttling 的通俗易懂的文章🚀
文章来源:https://dev.to/jeetvora331/difference- Between-microtask-and-macrotask-queue-in-the-event-loop-4i4i