1. 定义与常见类型
宏任务:
代表较大的、离散的工作单元。
常见类型:
setTimeout
、setInterval
、I/O操作(如文件读取)、UI渲染、整体脚本(<script>
)的执行。
微任务:
代表需要尽快执行的小任务,通常与当前宏任务相关。
常见类型:
Promise
的回调(then/catch/finally
)、MutationObserver
、process.nextTick
(Node.js 环境)。
2. 执行顺序
事件循环按以下步骤运行:
执行一个宏任务(如初始脚本或
setTimeout
回调)。执行所有微任务:当前宏任务结束后,依次执行微任务队列中的所有任务(包括执行过程中新添加的微任务)。
UI渲染(如果需要):浏览器可能在此阶段更新视图。
重复循环:取下一个宏任务执行,依此类推。
3. 关键规则
微任务优先:每个宏任务执行完毕后,必须清空微任务队列,才能执行下一个宏任务。
微任务递归执行:若微任务中产生新的微任务,这些新任务会继续在当前阶段执行,直到队列为空。
宏任务按队列顺序执行:新宏任务会被添加到队列末尾,依次处理。
4. 示例分析
示例 1:基础顺序
console.log("start"); setTimeout(() => console.log("setTimeout"), 0); Promise.resolve().then(() => console.log("promise")); console.log("end");
输出:start → end → promise → setTimeout
解析:
主脚本(宏任务)执行,输出
start
和end
。微任务队列中的
Promise
回调先于setTimeout
执行。
示例 2:微任务嵌套
Promise.resolve().then(() => { console.log("微任务1"); Promise.resolve().then(() => console.log("微任务2")); });
输出:微任务1 → 微任务2
解析:微任务中产生的新微任务会在当前阶段立即执行。
示例 3:混合宏任务与微任务
setTimeout(() => { console.log("宏任务1"); Promise.resolve().then(() => console.log("微任务1")); }, 0); setTimeout(() => { console.log("宏任务2"); Promise.resolve().then(() => console.log("微任务2")); }, 0);
输出:宏任务1 → 微任务1 → 宏任务2 → 微任务2
解析:每个宏任务结束后,立即处理其产生的微任务。
5. 注意事项
避免微任务无限循环:在微任务中递归添加微任务会导致阻塞,阻碍后续宏任务执行。
Node.js 的差异:
process.nextTick
的优先级高于Promise
,属于微任务中的特例。UI渲染的时机:频繁的微任务可能延迟渲染,影响页面性能。
总结
宏任务:离散的异步任务,按队列顺序执行。
微任务:高优先级的任务,在宏任务结束后立即执行,确保快速响应。
事件循环:通过交替执行宏任务和清空微任务队列,实现高效异步处理。
理解两者的区别与执行顺序,能帮助开发者优化代码性能,避免异步逻辑中的意外行为。
0条评论
点击登录参与评论