在前端开发中,**宏任务(Macro Task)**和**微任务(Micro Task)**是 JavaScript 事件循环(Event Loop)中的两个重要概念。它们决定了异步代码的执行顺序。
---
### 1. **事件循环(Event Loop)**
JavaScript 是单线程的,通过事件循环机制处理异步任务。事件循环的核心是:
- **主线程**:执行同步代码。
- **任务队列**:存放异步任务的回调函数。
- **事件循环**:不断检查任务队列,将任务推入主线程执行。
任务队列分为两种:
- **宏任务队列**:存放宏任务。
- **微任务队列**:存放微任务。
---
### 2. **宏任务(Macro Task)**
宏任务是指需要较长时间执行的任务,通常包括:
- `setTimeout` 和 `setInterval` 的回调。
- `setImmediate`(Node.js 特有)。
- `requestAnimationFrame`(浏览器特有)。
- I/O 操作(如文件读写、网络请求)。
- UI 渲染(浏览器特有)。
**执行时机**:每次事件循环中,主线程会执行一个宏任务,然后检查微任务队列。
---
### 3. **微任务(Micro Task)**
微任务是指需要尽快执行的任务,通常包括:
- `Promise` 的回调(`then`、`catch`、`finally`)。
- `MutationObserver`(监听 DOM 变化)。
- `process.nextTick`(Node.js 特有)。
**执行时机**:每次宏任务执行完毕后,事件循环会清空微任务队列中的所有任务,然后再执行下一个宏任务。
---
### 4. **执行顺序**
事件循环的执行顺序如下:
1. 执行主线程的同步代码。
2. 执行当前宏任务。
3. 清空微任务队列中的所有任务。
4. 执行 UI 渲染(浏览器)。
5. 执行下一个宏任务。
---
### 5. **代码示例**
```javascript
console.log('1. 同步代码'); // 同步代码,立即执行
setTimeout(() => {
console.log('4. 宏任务 - setTimeout'); // 宏任务
}, 0);
Promise.resolve().then(() => {
console.log('3. 微任务 - Promise'); // 微任务
});
console.log('2. 同步代码'); // 同步代码,立即执行
```
**输出结果**:
```
1. 同步代码
2. 同步代码
3. 微任务 - Promise
4. 宏任务 - setTimeout
```
**解释**:
1. 同步代码立即执行。
2. `Promise` 的微任务在同步代码之后、宏任务之前执行。
3. `setTimeout` 的宏任务在微任务之后执行。
---
### 6. **宏任务和微任务的区别**
| 特性 | 宏任务(Macro Task) | 微任务(Micro Task) |
|-----------------|------------------------------------|------------------------------------|
| **执行时机** | 每次事件循环执行一个宏任务 | 每次宏任务执行后清空微任务队列 |
| **常见任务** | `setTimeout`、`setInterval`、I/O | `Promise`、`MutationObserver` |
| **优先级** | 较低 | 较高 |
| **队列类型** | 宏任务队列 | 微任务队列 |
---
### 7. **实际应用**
- **优化性能**:将高优先级任务放入微任务队列,确保尽快执行。
- **避免阻塞**:将耗时任务放入宏任务队列,避免阻塞主线程。
- **控制执行顺序**:通过微任务和宏任务的特性,控制异步代码的执行顺序。
---
### 总结
- **宏任务**:需要较长时间执行的任务,如 `setTimeout`、I/O 操作。
- **微任务**:需要尽快执行的任务,如 `Promise`、`MutationObserver`。
- **执行顺序**:同步代码 → 微任务 → 宏任务 → UI 渲染 → 下一个宏任务。
理解宏任务和微任务的机制,有助于更好地掌握 JavaScript 的异步编程和事件循环。