Node.js 事件循环机制
章节介绍
事件循环是 Node.js 的核心机制,它使得 Node.js 能够执行非阻塞 I/O 操作,尽管 JavaScript 是单线程的。理解事件循环对于编写高效的 Node.js 应用程序至关重要。本教程将详细介绍事件循环的工作原理、任务队列的类型以及代码执行顺序。
核心知识点
事件循环概述
Node.js 的事件循环是一个单线程的循环,用于处理异步操作和回调函数。
事件循环工作流程:
┌─────────────────────────────────────┐
│ Node.js 事件循环 │
├─────────────────────────────────────┤
│ 1. 执行同步代码 │
│ 2. 执行微任务队列 │
│ 3. 执行宏任务队列 │
│ 4. 重复步骤 2-3 │
└─────────────────────────────────────┘
任务队列:
┌─────────────────────────────────────┐
│ 微任务队列(Microtask) │
│ - Promise.then/catch/finally │
│ - process.nextTick │
│ - queueMicrotask │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 宏任务队列(Macrotask) │
│ - setTimeout/setInterval │
│ - setImmediate │
│ - I/O 回调 │
│ - close 回调 │
└─────────────────────────────────────┘事件循环的各个阶段
Node.js 的事件循环分为多个阶段,每个阶段都有自己的任务队列。
事件循环阶段:
┌─────────────────────────────────────┐
│ 1. Timers 阶段 │
│ - setTimeout/setInterval 回调 │
├─────────────────────────────────────┤
│ 2. Pending Callbacks 阶段 │
│ - I/O 异常回调 │
├─────────────────────────────────────┤
│ 3. Idle, Prepare 阶段 │
│ - 内部使用 │
├─────────────────────────────────────┤
│ 4. Poll 阶段 │
│ - I/O 回调 │
│ - 新的 I/O 事件 │
├─────────────────────────────────────┤
│ 5. Check 阶段 │
│ - setImmediate 回调 │
├─────────────────────────────────────┤
│ 6. Close Callbacks 阶段 │
│ - close 事件回调 │
└─────────────────────────────────────┘微任务与宏任务
理解微任务和宏任务的区别对于掌握事件循环至关重要。
// 微任务(Microtask)
// - Promise.then/catch/finally
// - process.nextTick
// - queueMicrotask
// 宏任务(Macrotask)
// - setTimeout/setInterval
// - setImmediate
// - I/O 回调
// - close 回调
// 示例 1:微任务优先于宏任务
console.log('1. 同步代码');
Promise.resolve().then(() => {
console.log('2. 微任务(Promise.then)');
});
setTimeout(() => {
console.log('3. 宏任务(setTimeout)');
}, 0);
console.log('4. 同步代码');
// 输出顺序:
// 1. 同步代码
// 4. 同步代码
// 2. 微任务(Promise.then)
// 3. 宏任务(setTimeout)
// 示例 2:process.nextTick 优先于 Promise.then
console.log('1. 同步代码');
process.nextTick(() => {
console.log('2. 微任务(process.nextTick)');
});
Promise.resolve().then(() => {
console.log('3. 微任务(Promise.then)');
});
console.log('4. 同步代码');
// 输出顺序:
// 1. 同步代码
// 4. 同步代码
// 2. 微任务(process.nextTick)
// 3. 微任务(Promise.then)
// 示例 3:微任务队列会全部执行完毕
console.log('1. 同步代码');
Promise.resolve().then(() => {
console.log('2. 微任务 1');
Promise.resolve().then(() => {
console.log('3. 微任务 2(嵌套)');
});
});
Promise.resolve().then(() => {
console.log('4. 微任务 3');
});
console.log('5. 同步代码');
// 输出顺序:
// 1. 同步代码
// 5. 同步代码
// 2. 微任务 1
// 4. 微任务 3
// 3. 微任务 2(嵌套)事件循环示例
// 示例 1:基本的事件循环
console.log('开始');
setTimeout(() => {
console.log('setTimeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
console.log('结束');
// 输出顺序:
// 开始
// 结束
// Promise 1
// setTimeout 1
// 示例 2:嵌套的异步操作
console.log('1. 同步代码');
setTimeout(() => {
console.log('2. setTimeout 1');
Promise.resolve().then(() => {
console.log('3. Promise 1(在 setTimeout 中)');
});
}, 0);
Promise.resolve().then(() => {
console.log('4. Promise 2');
setTimeout(() => {
console.log('5. setTimeout 2(在 Promise 中)');
}, 0);
});
console.log('6. 同步代码');
// 输出顺序:
// 1. 同步代码
// 6. 同步代码
// 4. Promise 2
// 2. setTimeout 1
// 3. Promise 1(在 setTimeout 中)
// 5. setTimeout 2(在 Promise 中)
// 示例 3:setImmediate 与 setTimeout
console.log('1. 同步代码');
setImmediate(() => {
console.log('2. setImmediate');
});
setTimeout(() => {
console.log('3. setTimeout');
}, 0);
console.log('4. 同步代码');
// 输出顺序(可能不同):
// 1. 同步代码
// 4. 同步代码
// 2. setImmediate
// 3. setTimeout
// 或:
// 1. 同步代码
// 4. 同步代码
// 3. setTimeout
// 2. setImmediate
// 注意:在 I/O 回调中,setImmediate 总是先于 setTimeoutprocess.nextTick
process.nextTick 是一个特殊的微任务,它在当前操作完成后立即执行。
// 示例 1:process.nextTick 的执行时机
console.log('1. 同步代码');
process.nextTick(() => {
console.log('2. process.nextTick');
});
console.log('3. 同步代码');
// 输出顺序:
// 1. 同步代码
// 3. 同步代码
// 2. process.nextTick
// 示例 2:process.nextTick 可以递归调用
console.log('1. 同步代码');
let count = 0;
function recursiveNextTick() {
if (count < 3) {
count++;
console.log(`2. process.nextTick ${count}`);
process.nextTick(recursiveNextTick);
}
}
recursiveNextTick();
console.log('3. 同步代码');
// 输出顺序:
// 1. 同步代码
// 3. 同步代码
// 2. process.nextTick 1
// 2. process.nextTick 2
// 2. process.nextTick 3
// 示例 3:process.nextTick 与 Promise.then
console.log('1. 同步代码');
process.nextTick(() => {
console.log('2. process.nextTick 1');
});
Promise.resolve().then(() => {
console.log('3. Promise.then 1');
});
process.nextTick(() => {
console.log('4. process.nextTick 2');
});
Promise.resolve().then(() => {
console.log('5. Promise.then 2');
});
console.log('6. 同步代码');
// 输出顺序:
// 1. 同步代码
// 6. 同步代码
// 2. process.nextTick 1
// 4. process.nextTick 2
// 3. Promise.then 1
// 5. Promise.then 2setImmediate
setImmediate 在当前事件循环的 Check 阶段执行。
// 示例 1:setImmediate 的基本使用
console.log('1. 同步代码');
setImmediate(() => {
console.log('2. setImmediate');
});
console.log('3. 同步代码');
// 输出顺序:
// 1. 同步代码
// 3. 同步代码
// 2. setImmediate
// 示例 2:setImmediate 与 setTimeout
console.log('1. 同步代码');
setImmediate(() => {
console.log('2. setImmediate');
});
setTimeout(() => {
console.log('3. setTimeout');
}, 0);
console.log('4. 同步代码');
// 输出顺序(可能不同):
// 1. 同步代码
// 4. 同步代码
// 2. setImmediate
// 3. setTimeout
// 或:
// 1. 同步代码
// 4. 同步代码
// 3. setTimeout
// 2. setImmediate
// 示例 3:在 I/O 回调中,setImmediate 总是先于 setTimeout
const fs = require('fs');
fs.readFile(__filename, () => {
console.log('1. I/O 回调开始');
setImmediate(() => {
console.log('2. setImmediate(在 I/O 回调中)');
});
setTimeout(() => {
console.log('3. setTimeout(在 I/O 回调中)');
}, 0);
console.log('4. I/O 回调结束');
});
// 输出顺序:
// 1. I/O 回调开始
// 4. I/O 回调结束
// 2. setImmediate(在 I/O 回调中)
// 3. setTimeout(在 I/O 回调中)实用案例分析
案例 1:事件循环分析器
创建一个能够分析代码执行顺序的事件循环分析器。
// event-loop-analyzer.js
class EventLoopAnalyzer {
constructor() {
this.timeline = [];
this.currentPhase = 'sync';
}
// 记录事件
log(message, type = 'sync') {
const timestamp = Date.now();
this.timeline.push({
timestamp,
message,
type,
phase: this.currentPhase
});
console.log(`[${type.toUpperCase()}] ${message}`);
}
// 分析执行顺序
analyze() {
console.log('\n=== 事件循环分析 ===');
console.log(`总事件数:${this.timeline.length}`);
const typeCount = {};
this.timeline.forEach(event => {
typeCount[event.type] = (typeCount[event.type] || 0) + 1;
});
console.log('\n事件类型统计:');
Object.entries(typeCount).forEach(([type, count]) => {
console.log(` ${type}: ${count}`);
});
console.log('\n执行时间线:');
this.timeline.forEach((event, index) => {
const timeDiff = index > 0
? event.timestamp - this.timeline[index - 1].timestamp
: 0;
console.log(` ${index + 1}. [${event.type.toUpperCase()}] ${event.message} (+${timeDiff}ms)`);
});
}
// 模拟同步代码
simulateSync(callback) {
this.currentPhase = 'sync';
callback();
}
// 模拟微任务
simulateMicrotask(callback) {
this.currentPhase = 'microtask';
callback();
}
// 模拟宏任务
simulateMacrotask(callback) {
this.currentPhase = 'macrotask';
callback();
}
}
// 使用示例
const analyzer = new EventLoopAnalyzer();
console.log('=== 事件循环模拟 ===');
analyzer.simulateSync(() => {
analyzer.log('同步代码 1');
});
analyzer.simulateMicrotask(() => {
analyzer.log('微任务 1(Promise.then)');
});
analyzer.simulateMicrotask(() => {
analyzer.log('微任务 2(process.nextTick)');
});
analyzer.simulateMacrotask(() => {
analyzer.log('宏任务 1(setTimeout)');
});
analyzer.simulateSync(() => {
analyzer.log('同步代码 2');
});
analyzer.simulateMicrotask(() => {
analyzer.log('微任务 3(Promise.then)');
});
analyzer.simulateMacrotask(() => {
analyzer.log('宏任务 2(setImmediate)');
});
analyzer.analyze();案例 2:异步任务调度器
创建一个能够调度和执行异步任务的调度器。
// async-task-scheduler.js
class AsyncTaskScheduler {
constructor() {
this.tasks = new Map();
this.taskId = 0;
}
// 添加微任务
addMicrotask(fn, ...args) {
const id = ++this.taskId;
const task = {
id,
type: 'microtask',
fn,
args,
createdAt: Date.now()
};
this.tasks.set(id, task);
process.nextTick(() => {
try {
task.result = fn(...args);
task.status = 'completed';
task.completedAt = Date.now();
} catch (error) {
task.error = error;
task.status = 'failed';
task.completedAt = Date.now();
}
});
return id;
}
// 添加 Promise 微任务
addPromiseTask(fn, ...args) {
const id = ++this.taskId;
const task = {
id,
type: 'promise',
fn,
args,
createdAt: Date.now()
};
this.tasks.set(id, task);
Promise.resolve().then(async () => {
try {
task.result = await fn(...args);
task.status = 'completed';
task.completedAt = Date.now();
} catch (error) {
task.error = error;
task.status = 'failed';
task.completedAt = Date.now();
}
});
return id;
}
// 添加 setTimeout 宏任务
addTimeoutTask(fn, delay, ...args) {
const id = ++this.taskId;
const task = {
id,
type: 'timeout',
fn,
delay,
args,
createdAt: Date.now()
};
this.tasks.set(id, task);
setTimeout(() => {
try {
task.result = fn(...args);
task.status = 'completed';
task.completedAt = Date.now();
} catch (error) {
task.error = error;
task.status = 'failed';
task.completedAt = Date.now();
}
}, delay);
return id;
}
// 添加 setImmediate 宏任务
addImmediateTask(fn, ...args) {
const id = ++this.taskId;
const task = {
id,
type: 'immediate',
fn,
args,
createdAt: Date.now()
};
this.tasks.set(id, task);
setImmediate(() => {
try {
task.result = fn(...args);
task.status = 'completed';
task.completedAt = Date.now();
} catch (error) {
task.error = error;
task.status = 'failed';
task.completedAt = Date.now();
}
});
return id;
}
// 获取任务状态
getTaskStatus(id) {
return this.tasks.get(id);
}
// 等待任务完成
async waitForTask(id) {
return new Promise((resolve, reject) => {
const checkTask = () => {
const task = this.tasks.get(id);
if (!task) {
reject(new Error('Task not found'));
return;
}
if (task.status === 'completed') {
resolve(task.result);
} else if (task.status === 'failed') {
reject(task.error);
} else {
process.nextTick(checkTask);
}
};
checkTask();
});
}
// 获取所有任务
getAllTasks() {
return Array.from(this.tasks.values());
}
// 清除已完成的任务
clearCompletedTasks() {
this.tasks.forEach((task, id) => {
if (task.status === 'completed' || task.status === 'failed') {
this.tasks.delete(id);
}
});
}
}
// 使用示例
const scheduler = new AsyncTaskScheduler();
// 添加各种任务
const task1 = scheduler.addMicrotask(() => {
console.log('微任务 1 执行');
return '微任务 1 结果';
});
const task2 = scheduler.addPromiseTask(async () => {
console.log('Promise 任务执行');
await new Promise(resolve => setTimeout(resolve, 100));
return 'Promise 任务结果';
});
const task3 = scheduler.addTimeoutTask(() => {
console.log('setTimeout 任务执行');
return 'setTimeout 任务结果';
}, 50);
const task4 = scheduler.addImmediateTask(() => {
console.log('setImmediate 任务执行');
return 'setImmediate 任务结果';
});
// 等待任务完成
(async () => {
try {
const result1 = await scheduler.waitForTask(task1);
console.log('任务 1 结果:', result1);
const result2 = await scheduler.waitForTask(task2);
console.log('任务 2 结果:', result2);
const result3 = await scheduler.waitForTask(task3);
console.log('任务 3 结果:', result3);
const result4 = await scheduler.waitForTask(task4);
console.log('任务 4 结果:', result4);
console.log('\n所有任务状态:');
const allTasks = scheduler.getAllTasks();
allTasks.forEach(task => {
console.log(`任务 ${task.id}: ${task.type} - ${task.status}`);
console.log(` 执行时间:${task.completedAt - task.createdAt}ms`);
});
} catch (error) {
console.error('任务执行失败:', error);
}
})();案例 3:事件循环可视化
创建一个能够可视化事件循环过程的工具。
// event-loop-visualizer.js
class EventLoopVisualizer {
constructor() {
this.phases = {
sync: [],
microtask: [],
macrotask: []
};
this.executionOrder = [];
}
// 添加同步任务
addSyncTask(name) {
this.phases.sync.push({
name,
type: 'sync',
timestamp: Date.now()
});
}
// 添加微任务
addMicrotask(name) {
this.phases.microtask.push({
name,
type: 'microtask',
timestamp: Date.now()
});
}
// 添加宏任务
addMacrotask(name) {
this.phases.macrotask.push({
name,
type: 'macrotask',
timestamp: Date.now()
});
}
// 记录执行
recordExecution(phase, task) {
this.executionOrder.push({
phase,
task,
timestamp: Date.now()
});
}
// 可视化执行过程
visualize() {
console.log('\n=== 事件循环可视化 ===\n');
// 显示任务队列
console.log('任务队列:');
console.log('┌─────────────────────────────────────┐');
console.log('│ 同步任务队列: │');
this.phases.sync.forEach((task, index) => {
console.log(`│ ${index + 1}. ${task.name} │`);
});
console.log('├─────────────────────────────────────┤');
console.log('│ 微任务队列: │');
this.phases.microtask.forEach((task, index) => {
console.log(`│ ${index + 1}. ${task.name} │`);
});
console.log('├─────────────────────────────────────┤');
console.log('│ 宏任务队列: │');
this.phases.macrotask.forEach((task, index) => {
console.log(`│ ${index + 1}. ${task.name} │`);
});
console.log('└─────────────────────────────────────┘\n');
// 显示执行顺序
console.log('执行顺序:');
this.executionOrder.forEach((execution, index) => {
const timeDiff = index > 0
? execution.timestamp - this.executionOrder[index - 1].timestamp
: 0;
console.log(`${index + 1}. [${execution.phase.toUpperCase()}] ${execution.task.name} (+${timeDiff}ms)`);
});
}
// 模拟事件循环
simulate() {
console.log('=== 模拟事件循环 ===\n');
// 执行同步任务
console.log('执行同步任务:');
while (this.phases.sync.length > 0) {
const task = this.phases.sync.shift();
this.recordExecution('sync', task);
console.log(` 执行:${task.name}`);
}
// 执行微任务
console.log('\n执行微任务:');
while (this.phases.microtask.length > 0) {
const task = this.phases.microtask.shift();
this.recordExecution('microtask', task);
console.log(` 执行:${task.name}`);
}
// 执行宏任务
console.log('\n执行宏任务:');
while (this.phases.macrotask.length > 0) {
const task = this.phases.macrotask.shift();
this.recordExecution('macrotask', task);
console.log(` 执行:${task.name}`);
}
console.log('\n事件循环完成');
}
}
// 使用示例
const visualizer = new EventLoopVisualizer();
// 添加任务
visualizer.addSyncTask('同步代码 1');
visualizer.addSyncTask('同步代码 2');
visualizer.addMicrotask('Promise.then 1');
visualizer.addMicrotask('process.nextTick 1');
visualizer.addMicrotask('Promise.then 2');
visualizer.addMacrotask('setTimeout 1');
visualizer.addMacrotask('setImmediate 1');
visualizer.addMacrotask('setTimeout 2');
// 模拟事件循环
visualizer.simulate();
// 可视化结果
visualizer.visualize();代码示例
示例 1:事件循环测试
// event-loop-test.js
console.log('=== 事件循环测试 ===\n');
// 测试 1:基本顺序
console.log('测试 1:基本顺序');
console.log('1. 同步代码');
setTimeout(() => {
console.log('4. setTimeout');
}, 0);
Promise.resolve().then(() => {
console.log('3. Promise.then');
});
console.log('2. 同步代码');
// 测试 2:嵌套异步操作
console.log('\n测试 2:嵌套异步操作');
console.log('1. 同步代码');
setTimeout(() => {
console.log('3. setTimeout 1');
Promise.resolve().then(() => {
console.log('5. Promise.then(嵌套)');
});
setTimeout(() => {
console.log('6. setTimeout(嵌套)');
}, 0);
}, 0);
Promise.resolve().then(() => {
console.log('2. Promise.then');
setTimeout(() => {
console.log('4. setTimeout(在 Promise 中)');
}, 0);
});
// 测试 3:process.nextTick 优先级
console.log('\n测试 3:process.nextTick 优先级');
console.log('1. 同步代码');
process.nextTick(() => {
console.log('3. process.nextTick 1');
});
Promise.resolve().then(() => {
console.log('4. Promise.then');
});
process.nextTick(() => {
console.log('2. process.nextTick 2');
});
console.log('5. 同步代码');
// 测试 4:setImmediate 与 setTimeout
console.log('\n测试 4:setImmediate 与 setTimeout');
console.log('1. 同步代码');
setImmediate(() => {
console.log('3. setImmediate');
});
setTimeout(() => {
console.log('4. setTimeout');
}, 0);
console.log('2. 同步代码');
// 测试 5:I/O 回调中的顺序
console.log('\n测试 5:I/O 回调中的顺序');
const fs = require('fs');
fs.readFile(__filename, () => {
console.log('1. I/O 回调开始');
setImmediate(() => {
console.log('3. setImmediate(在 I/O 回调中)');
});
setTimeout(() => {
console.log('4. setTimeout(在 I/O 回调中)');
}, 0);
Promise.resolve().then(() => {
console.log('2. Promise.then(在 I/O 回调中)');
});
console.log('5. I/O 回调结束');
});示例 2:异步操作顺序分析
// async-order-analyzer.js
class AsyncOrderAnalyzer {
constructor() {
this.events = [];
}
// 记录事件
record(type, description) {
const timestamp = Date.now();
this.events.push({ type, description, timestamp });
console.log(`[${type.toUpperCase()}] ${description}`);
}
// 分析执行顺序
analyze() {
console.log('\n=== 执行顺序分析 ===');
console.log(`总事件数:${this.events.length}\n`);
const typeGroups = {};
this.events.forEach(event => {
if (!typeGroups[event.type]) {
typeGroups[event.type] = [];
}
typeGroups[event.type].push(event);
});
Object.entries(typeGroups).forEach(([type, events]) => {
console.log(`${type.toUpperCase()} 事件(${events.length} 个):`);
events.forEach((event, index) => {
const timeDiff = index > 0
? event.timestamp - events[index - 1].timestamp
: 0;
console.log(` ${index + 1}. ${event.description} (+${timeDiff}ms)`);
});
console.log();
});
}
}
// 使用示例
const analyzer = new AsyncOrderAnalyzer();
console.log('=== 异步操作顺序测试 ===\n');
analyzer.record('sync', '同步代码 1');
setTimeout(() => {
analyzer.record('timeout', 'setTimeout 1');
}, 0);
Promise.resolve().then(() => {
analyzer.record('promise', 'Promise.then 1');
setTimeout(() => {
analyzer.record('timeout', 'setTimeout 2(嵌套)');
}, 0);
});
process.nextTick(() => {
analyzer.record('nexttick', 'process.nextTick');
});
setImmediate(() => {
analyzer.record('immediate', 'setImmediate');
});
analyzer.record('sync', '同步代码 2');
setTimeout(() => {
analyzer.record('timeout', 'setTimeout 3');
}, 100);
Promise.resolve().then(() => {
analyzer.record('promise', 'Promise.then 2');
});
setTimeout(() => {
analyzer.analyze();
}, 200);示例 3:事件循环性能测试
// event-loop-performance.js
class EventLoopPerformanceTester {
constructor() {
this.results = [];
}
// 测试同步操作性能
testSync(iterations) {
console.log(`\n测试同步操作(${iterations} 次迭代)`);
const start = Date.now();
for (let i = 0; i < iterations; i++) {
const result = i * 2;
}
const duration = Date.now() - start;
console.log(`执行时间:${duration}ms`);
console.log(`平均每次:${(duration / iterations).toFixed(4)}ms`);
this.results.push({
type: 'sync',
iterations,
duration,
avgTime: duration / iterations
});
}
// 测试 process.nextTick 性能
testNextTick(iterations) {
console.log(`\n测试 process.nextTick(${iterations} 次迭代)`);
const start = Date.now();
let completed = 0;
function recursiveNextTick() {
if (completed < iterations) {
completed++;
process.nextTick(recursiveNextTick);
} else {
const duration = Date.now() - start;
console.log(`执行时间:${duration}ms`);
console.log(`平均每次:${(duration / iterations).toFixed(4)}ms`);
this.results.push({
type: 'nexttick',
iterations,
duration,
avgTime: duration / iterations
});
}
}
recursiveNextTick();
}
// 测试 Promise 性能
testPromise(iterations) {
console.log(`\n测试 Promise(${iterations} 次迭代)`);
const start = Date.now();
let completed = 0;
function recursivePromise() {
if (completed < iterations) {
completed++;
Promise.resolve().then(recursivePromise);
} else {
const duration = Date.now() - start;
console.log(`执行时间:${duration}ms`);
console.log(`平均每次:${(duration / iterations).toFixed(4)}ms`);
this.results.push({
type: 'promise',
iterations,
duration,
avgTime: duration / iterations
});
}
}
recursivePromise();
}
// 测试 setTimeout 性能
testTimeout(iterations, delay) {
console.log(`\n测试 setTimeout(${iterations} 次迭代,延迟 ${delay}ms)`);
const start = Date.now();
let completed = 0;
function recursiveTimeout() {
if (completed < iterations) {
completed++;
setTimeout(recursiveTimeout, delay);
} else {
const duration = Date.now() - start;
console.log(`执行时间:${duration}ms`);
console.log(`平均每次:${(duration / iterations).toFixed(4)}ms`);
this.results.push({
type: 'timeout',
iterations,
delay,
duration,
avgTime: duration / iterations
});
}
}
recursiveTimeout();
}
// 测试 setImmediate 性能
testImmediate(iterations) {
console.log(`\n测试 setImmediate(${iterations} 次迭代)`);
const start = Date.now();
let completed = 0;
function recursiveImmediate() {
if (completed < iterations) {
completed++;
setImmediate(recursiveImmediate);
} else {
const duration = Date.now() - start;
console.log(`执行时间:${duration}ms`);
console.log(`平均每次:${(duration / iterations).toFixed(4)}ms`);
this.results.push({
type: 'immediate',
iterations,
duration,
avgTime: duration / iterations
});
}
}
recursiveImmediate();
}
// 生成性能报告
generateReport() {
console.log('\n=== 性能测试报告 ===\n');
const report = this.results.map(result => {
return {
类型: result.type,
迭代次数: result.iterations,
总时间: `${result.duration}ms`,
平均时间: `${result.avgTime.toFixed(4)}ms`
};
});
console.table(report);
}
}
// 使用示例
const tester = new EventLoopPerformanceTester();
// 测试同步操作
tester.testSync(1000000);
// 测试 process.nextTick
tester.testNextTick(10000);
// 测试 Promise
tester.testPromise(10000);
// 测试 setTimeout
tester.testTimeout(1000, 0);
// 测试 setImmediate
tester.testImmediate(10000);
// 生成性能报告
setTimeout(() => {
tester.generateReport();
}, 5000);实现技巧与注意事项
事件循环使用建议
- 理解执行顺序:掌握微任务和宏任务的执行顺序
- 避免阻塞事件循环:不要在同步代码中执行耗时操作
- 合理使用异步操作:根据需求选择合适的异步方法
- 注意递归调用:避免无限递归导致事件循环阻塞
性能优化建议
- 使用 process.nextTick:对于需要立即执行的任务
- 使用 Promise:对于链式异步操作
- 使用 setImmediate:在 I/O 回调中优先使用
- 避免过多的微任务:防止微任务队列过长
调试技巧
- 使用 console.log:在关键位置打印日志
- 分析执行顺序:使用事件循环分析器
- 监控性能:使用性能测试工具
- 避免回调地狱:使用 Promise 或 async/await
常见问题与解决方案
问题 1:事件循环阻塞
// 问题代码:同步代码阻塞事件循环
function heavyComputation() {
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += i;
}
return sum;
}
console.log('开始计算');
const result = heavyComputation();
console.log('计算完成', result);
// 在计算期间,事件循环被阻塞
// 解决方案:使用 setImmediate 分割任务
function heavyComputationAsync(callback) {
let sum = 0;
let i = 0;
const chunkSize = 10000000;
function processChunk() {
const end = Math.min(i + chunkSize, 1000000000);
for (; i < end; i++) {
sum += i;
}
if (i < 1000000000) {
setImmediate(processChunk);
} else {
callback(sum);
}
}
processChunk();
}
console.log('开始计算');
heavyComputationAsync((result) => {
console.log('计算完成', result);
});
console.log('事件循环未被阻塞');问题 2:微任务队列过长
// 问题代码:微任务队列过长
function createMicrotasks() {
for (let i = 0; i < 100000; i++) {
Promise.resolve().then(() => {
console.log('微任务', i);
});
}
}
createMicrotasks();
// 微任务队列过长,影响性能
// 解决方案:使用宏任务分割微任务
function createMicrotasksOptimized() {
let i = 0;
const chunkSize = 1000;
function processChunk() {
const end = Math.min(i + chunkSize, 100000);
for (; i < end; i++) {
Promise.resolve().then(() => {
console.log('微任务', i);
});
}
if (i < 100000) {
setImmediate(processChunk);
}
}
processChunk();
}
createMicrotasksOptimized();问题 3:递归调用导致栈溢出
// 问题代码:递归调用导致栈溢出
function recursiveFunction(n) {
if (n > 0) {
recursiveFunction(n - 1);
}
}
recursiveFunction(100000);
// RangeError: Maximum call stack size exceeded
// 解决方案:使用 process.nextTick 避免栈溢出
function recursiveFunctionAsync(n) {
if (n > 0) {
process.nextTick(() => {
recursiveFunctionAsync(n - 1);
});
}
}
recursiveFunctionAsync(100000);
// 不会导致栈溢出问题 4:异步操作顺序不确定
// 问题代码:异步操作顺序不确定
console.log('1');
setTimeout(() => {
console.log('2');
}, 0);
Promise.resolve().then(() => {
console.log('3');
});
console.log('4');
// 输出顺序:1, 4, 3, 2
// 解决方案:使用 Promise 或 async/await 控制顺序
async function controlledOrder() {
console.log('1');
await new Promise(resolve => {
setTimeout(() => {
console.log('2');
resolve();
}, 0);
});
await Promise.resolve().then(() => {
console.log('3');
});
console.log('4');
}
controlledOrder();
// 输出顺序:1, 2, 3, 4总结
本教程详细介绍了 Node.js 的事件循环机制,包括事件循环的工作原理、任务队列的类型、微任务与宏任务的区别等重要内容。掌握事件循环对于理解 Node.js 的异步编程模型至关重要。
通过本集的学习,您应该能够:
- 理解 Node.js 事件循环的工作原理
- 掌握微任务和宏任务的区别
- 理解 process.nextTick 和 setImmediate 的使用场景
- 分析代码的执行顺序
- 避免事件循环阻塞
- 优化异步操作性能
在下一集中,我们将学习 Node.js 的回调函数,这是 Node.js 异步编程的基础。继续加油,您的 Node.js 技能正在不断提升!