Node.js 宏任务与微任务快速参考卡
🚀 微任务 (Micro Tasks)
执行时机: 在每个事件循环阶段之间执行
优先级排序 (从高到低):
| 优先级 | API | 说明 | 示例 |
|---|---|---|---|
| 最高 | process.nextTick() | Node.js特有,最高优先级 | process.nextTick(() => {}) |
| 高 | Promise.then() | Promise成功回调 | Promise.resolve().then(() => {}) |
| 高 | Promise.catch() | Promise失败回调 | Promise.reject().catch(() => {}) |
| 高 | Promise.finally() | Promise完成回调 | Promise.resolve().finally(() => {}) |
| 高 | async/await | Promise语法糖 | await Promise.resolve() |
| 中 | queueMicrotask() | 通用微任务API | queueMicrotask(() => {}) |
⏰ 宏任务 (Macro Tasks)
执行时机: 按事件循环的6个阶段顺序执行
Timer 阶段
| API | 说明 | 示例 |
|---|---|---|
setTimeout() | 延时执行 | setTimeout(() => {}, 1000) |
setInterval() | 间隔执行 | setInterval(() => {}, 1000) |
clearTimeout() | 清除延时器 | clearTimeout(timerId) |
clearInterval() | 清除间隔器 | clearInterval(intervalId) |
Poll 阶段 (I/O操作)
| 分类 | API | 说明 | 示例 |
|---|---|---|---|
| 文件系统 | fs.readFile() | 读取文件 | fs.readFile('file.txt', callback) |
| 文件系统 | fs.writeFile() | 写入文件 | fs.writeFile('file.txt', data, callback) |
| 文件系统 | fs.stat() | 文件状态 | fs.stat('file.txt', callback) |
| 文件系统 | fs.readdir() | 读取目录 | fs.readdir('./', callback) |
| 文件系统 | fs.mkdir() | 创建目录 | fs.mkdir('dir', callback) |
| 文件系统 | fs.unlink() | 删除文件 | fs.unlink('file.txt', callback) |
| 网络 | http.request() | HTTP请求 | http.request(options, callback) |
| 网络 | http.get() | HTTP GET | http.get(url, callback) |
| 网络 | https.request() | HTTPS请求 | https.request(options, callback) |
| DNS | dns.lookup() | DNS查询 | dns.lookup('google.com', callback) |
| DNS | dns.resolve() | DNS解析 | dns.resolve('google.com', callback) |
| TCP | net.connect() | TCP连接 | net.connect(port, host, callback) |
| 流 | stream.read() | 流读取 | stream.on('data', callback) |
| 加密 | crypto.pbkdf2() | 密码派生 | crypto.pbkdf2(password, salt, iterations, keylen, digest, callback) |
| 压缩 | zlib.gzip() | Gzip压缩 | zlib.gzip(buffer, callback) |
Check 阶段
| API | 说明 | 示例 |
|---|---|---|
setImmediate() | 立即执行 | setImmediate(() => {}) |
clearImmediate() | 清除立即执行 | clearImmediate(immediateId) |
Close 阶段
| API | 说明 | 示例 |
|---|---|---|
socket.on('close') | Socket关闭 | socket.on('close', callback) |
server.on('close') | 服务器关闭 | server.on('close', callback) |
process.on('exit') | 进程退出 | process.on('exit', callback) |
📊 执行顺序总结
1. 同步代码 (立即执行)
↓
2. 微任务队列
- process.nextTick (最高优先级)
- Promise.then/catch/finally
- queueMicrotask
↓
3. 宏任务 (按事件循环阶段)
- Timer阶段: setTimeout, setInterval
- Poll阶段: I/O操作回调
- Check阶段: setImmediate
- Close阶段: 关闭事件回调
↓
4. 重复步骤2-3,直到所有任务完成⚠️ 特殊情况
I/O回调中的执行顺序
javascript
fs.readFile('file.txt', () => {
setTimeout(() => console.log('setTimeout'), 0); // 后执行
setImmediate(() => console.log('setImmediate')); // 先执行
});微任务的嵌套
javascript
process.nextTick(() => {
console.log('nextTick 1');
process.nextTick(() => console.log('nextTick 2')); // 会在同一轮执行
});💡 最佳实践
✅ 推荐做法
- 优先使用
Promise而不是process.nextTick - 使用
setImmediate而不是setTimeout(fn, 0) - 避免在微任务中执行CPU密集型操作
- 合理控制微任务数量,防止阻塞事件循环
❌ 避免的做法
javascript
// 危险:无限递归微任务
function badRecursion() {
process.nextTick(badRecursion); // 会阻塞事件循环
}
// 安全:使用宏任务
function goodRecursion() {
setImmediate(goodRecursion); // 不会阻塞事件循环
}🔍 调试技巧
查看执行顺序
javascript
console.trace('当前调用栈');
process.nextTick(() => console.trace('nextTick'));
Promise.resolve().then(() => console.trace('Promise'));
setTimeout(() => console.trace('setTimeout'), 0);监控事件循环延迟
javascript
const { performance } = require('perf_hooks');
function checkEventLoopDelay() {
const start = performance.now();
setImmediate(() => {
const delay = performance.now() - start;
console.log(`事件循环延迟: ${delay.toFixed(2)}ms`);
});
}📈 性能对比
基于测试结果,性能排序(从快到慢):
setImmediate- 最快的宏任务setTimeout- 中等性能的宏任务Promise.then- 最快的微任务process.nextTick- 较慢的微任务queueMicrotask- 最慢的微任务
记住: 微任务优先级高于宏任务,但过多的微任务会阻塞事件循环!