在浏览器中,JavaScript 代码执行是由事件循环(Event Loop)控制的。当 JavaScript 引擎遇到异步任务时,它会将任务加入一个任务队列中,等待被执行。这些异步任务可以分为两类:microtask 和 macrotask。
Microtask
Microtask 也称为微任务,它们通常比 Macrotask 执行得更快。当 JavaScript 引擎处理完当前同步任务后,它会立即从 Microtask 队列中获取最先进入队列的任务并执行,直到 Microtask 队列为空为止。这意味着 Microtask 在当前事件循环周期内执行,不会延迟下一次事件循环周期的开始。
现代浏览器提供了许多 API,如 Promise、MutationObserver、Object.observe 等都会产生 Microtask。下面是一个使用 Promise 的示例代码:
console.log('script start'); Promise.resolve().then(() => console.log('promise')); console.log('script end');
上述代码输出的结果为:
script start script end promise
从上述代码可以看出,即使 Promise 是异步函数,但因为它是 Microtask,所以它的执行顺序比 Script 中的后续代码还要早。
Macrotask
Macrotask 也称为宏任务,它们相对于 Microtask 来说执行速度较慢。当 JavaScript 引擎处理完当前同步任务后,它会从 Macrotask 队列中获取最先进入队列的任务并执行。这意味着 Macrotask 在下一次事件循环周期内执行。
常见的 Macrotask 包括 setTimeout、setInterval、I/O 操作等。下面是一个使用 setTimeout 的示例代码:
console.log('script start'); setTimeout(() => console.log('timeout'), 0); console.log('script end');
上述代码输出的结果为:
script start script end timeout
从上述代码可以看出,即使 setTimeout 是异步函数,但由于它是 Macrotask,所以它的执行顺序比 Script 中的后续代码还要晚。
总结
了解 Microtask 和 Macrotask 在事件循环中的执行顺序和机制是编写高效 JavaScript 应用程序的关键之一。可以将任务尽可能地添加到 Microtask 中,以确保最快的响应时间。同时,避免在 Macrotask 中添加过多的任务,以避免阻塞事件循环。
以下是一些编写高效 JavaScript 应用程序的建议:
- 将需要立即执行的代码放在 Microtask 中。
- 尽量使用 Promise 来触发异步操作。
- 避免使用 setInterval,而是使用 setTimeout,并在回调函数中设置下一次超时。
- 最小化 DOM 操作,因为每次更改都会导致重新渲染页面。
最后,需要注意的是:对于 Macrotask 和 Microtask,浏览器兼容性有时会存在差异。在编写跨浏览器应用程序时,请确保您的代码能够在各种浏览器上正常运行。
参考资料
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6709