MST

星途 面试题库

面试题:JavaScript 事件循环中宏任务与微任务的执行顺序问题

请描述在 JavaScript 事件循环机制下,宏任务(macrotask)和微任务(microtask)的执行顺序,并举例说明常见的宏任务和微任务有哪些。
25.7万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

执行顺序

  1. 首先执行同步代码,这是主线程上的任务。
  2. 当同步代码执行完后,检查微任务队列,将微任务队列中的所有任务依次执行完。
  3. 微任务队列清空后,从宏任务队列中取出一个宏任务执行,执行完该宏任务后,再次检查微任务队列并执行其中所有任务。
  4. 重复上述过程,不断循环,每次宏任务执行完都会检查并执行微任务队列。

常见宏任务

  1. setTimeout:延迟指定时间后将回调函数放入宏任务队列。例如:
setTimeout(() => {
    console.log('setTimeout callback');
}, 0);
  1. setInterval:按照指定的时间间隔重复将回调函数放入宏任务队列。例如:
setInterval(() => {
    console.log('setInterval callback');
}, 1000);
  1. requestAnimationFrame:用于请求浏览器在下一次重绘之前调用指定的回调函数,它也是宏任务。常用于动画相关操作。例如:
function draw() {
    console.log('drawing');
    requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
  1. I/O操作:如网络请求(fetch等返回的Promise本身不是宏任务,但相关的底层I/O操作完成后触发的回调放入宏任务队列)、文件操作等,当操作完成后,将相应的回调放入宏任务队列。

常见微任务

  1. Promisethen回调:当Promise状态改变时,then方法中的回调会被放入微任务队列。例如:
Promise.resolve().then(() => {
    console.log('Promise then callback');
});
  1. MutationObserver:用于监视DOM变动,当DOM发生变化时,其回调会被放入微任务队列。例如:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF - 8">
    <title>Document</title>
</head>
<body>
    <div id="target">Hello</div>
    <script>
        const targetNode = document.getElementById('target');
        const config = { attributes: true, childList: true, subtree: true };
        const callback = (mutationsList, observer) => {
            console.log('DOM changed');
        };
        const observer = new MutationObserver(callback);
        observer.observe(targetNode, config);
        targetNode.textContent = 'World';
    </script>
</body>
</html>
  1. process.nextTick(仅Node.js环境):将回调函数放入微任务队列,并且会在当前调用栈清空后,下一次事件循环开始前执行,它的优先级比Promise.then更高。例如:
process.nextTick(() => {
    console.log('process.nextTick callback');
});
Promise.resolve().then(() => {
    console.log('Promise then callback');
});

上述代码在Node.js环境中,process.nextTick callback会先于Promise then callback输出。