JS 事件循环、单线程、宏任务、微任务
JS 事件循环、单线程、宏任务、微任务
1. 为什么是单线程
JS 最初为浏览器设计,需要操作 DOM。
如果多线程同时操作同一个 DOM 节点会产生冲突,所以 JS 引擎只有一个主线程。
但单线程意味着:同一时间只能做一件事 → 遇到耗时操作会阻塞页面。
所以需要异步机制来解决这个问题,这就是事件循环存在的原因。
2. 浏览器是多线程的
虽然 JS 引擎是单线程,但浏览器本身有多个线程协作:
- JS 引擎线程:执行 JS 代码(只有一个)
- GUI 渲染线程:渲染页面(与 JS 线程互斥)
- 网络请求线程:处理
fetch/XHR - 定时器线程:处理
setTimeout/setInterval - 事件触发线程:处理点击、键盘等事件
耗时任务交给其他线程处理,完成后把回调放入任务队列,JS 主线程空闲时再取出执行。
3. 什么是事件循环
事件循环就是 JS 主线程不断重复的工作流程:
执行一个宏任务
↓
清空所有微任务
↓
(可能)页面渲染
↓
取下一个宏任务
↓
...
4. 宏任务(Macrotask)
每次事件循环取一个宏任务执行。
常见宏任务:
- 整体脚本(
<script>,第一个宏任务) setTimeout/setInterval- UI 事件回调(
click、input) - I/O 回调
5. 微任务(Microtask)
优先级高于宏任务,每次宏任务结束后立刻清空所有微任务。
常见微任务:
Promise.then/catch/finallyqueueMicrotask()MutationObserver
关键:微任务不是"下一次循环",而是"当前宏任务结束后、下一个宏任务开始前"立刻执行。
6. 三者联系图
JS 主线程(单线程)
│
▼
┌─────────────────────────────────┐
│ 事件循环(Event Loop) │
│ │
│ 1. 取一个宏任务执行 │
│ ├── 整体 script(第一个) │
│ ├── setTimeout 回调 │
│ └── UI 事件回调 │
│ │
│ 2. 当前宏任务结束 │
│ └── 清空微任务队列 │
│ ├── Promise.then │
│ ├── queueMicrotask │
│ └── MutationObserver │
│ │
│ 3. 页面渲染(如有需要) │
│ │
│ 4. 取下一个宏任务 → 重复 │
└─────────────────────────────────┘
7. 通过例子验证
console.log("1"); // 同步
setTimeout(() => {
console.log("4"); // 宏任务
}, 0);
Promise.resolve().then(() => {
console.log("3"); // 微任务
});
console.log("2"); // 同步
执行过程:
- 整体脚本(第一个宏任务)开始
console.log('1')→ 输出1setTimeout回调放入宏任务队列Promise.then回调放入微任务队列console.log('2')→ 输出2- 当前宏任务结束,清空微任务 → 输出
3 - 进入下一个宏任务(setTimeout)→ 输出
4
结果:1 2 3 4
8. 微任务产生微任务的情况
微任务执行时如果又产生微任务,会继续追加到微任务队列尾部,在本轮全部清完:
Promise.resolve()
.then(() => {
console.log("微任务 1");
return Promise.resolve();
})
.then(() => {
console.log("微任务 2");
});
setTimeout(() => {
console.log("宏任务");
}, 0);
输出:微任务 1 → 微任务 2 → 宏任务
宏任务必须等所有微任务都清完才能执行。
9. 一句话总结
| 概念 | 说明 |
|---|---|
| 单线程 | JS 同一时间只做一件事 |
| 事件循环 | 不断取任务执行的机制 |
| 宏任务 | 每次循环取一个,粒度大 |
| 微任务 | 每个宏任务后立刻清空,优先级高 |
**单线程是原因,事件循环是解决方案,宏任务和微任务是执行队列的两个优先级层次。**输出:
微任务 1→微任务 2→宏任务
宏任务必须等所有微任务都清完才能执行。
9. 一句话总结
| 概念 | 说明 |
|---|---|
| 单线程 | JS 同一时间只做一件事 |
| 事件循环 | 不断取任务执行的机制 |
| 宏任务 | 每次循环取一个,粒度大 |
| 微任务 | 每个宏任务后立刻清空,优先级高 |
单线程是原因,事件循环是解决方案,宏任务和微任务是执行队列的两个优先级层次。
