面试题答案
一键面试执行顺序
- 首先执行同步代码,这是主线程上的任务。
- 当同步代码执行完后,检查微任务队列,将微任务队列中的所有任务依次执行完。
- 微任务队列清空后,从宏任务队列中取出一个宏任务执行,执行完该宏任务后,再次检查微任务队列并执行其中所有任务。
- 重复上述过程,不断循环,每次宏任务执行完都会检查并执行微任务队列。
常见宏任务
setTimeout
:延迟指定时间后将回调函数放入宏任务队列。例如:
setTimeout(() => {
console.log('setTimeout callback');
}, 0);
setInterval
:按照指定的时间间隔重复将回调函数放入宏任务队列。例如:
setInterval(() => {
console.log('setInterval callback');
}, 1000);
requestAnimationFrame
:用于请求浏览器在下一次重绘之前调用指定的回调函数,它也是宏任务。常用于动画相关操作。例如:
function draw() {
console.log('drawing');
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
- I/O操作:如网络请求(
fetch
等返回的Promise
本身不是宏任务,但相关的底层I/O操作完成后触发的回调放入宏任务队列)、文件操作等,当操作完成后,将相应的回调放入宏任务队列。
常见微任务
Promise
的then
回调:当Promise
状态改变时,then
方法中的回调会被放入微任务队列。例如:
Promise.resolve().then(() => {
console.log('Promise then callback');
});
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>
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
输出。