事件循环(Event Loop)是 JavaScript 处理异步操作的机制。JavaScript 是单线程的,通过事件循环实现非阻塞的异步执行。
JavaScript 执行环境包含:
console.log('1'); // 同步
setTimeout(() => {
console.log('2'); // 宏任务
}, 0);
Promise.resolve().then(() => {
console.log('3'); // 微任务
});
console.log('4'); // 同步
// 输出顺序:1, 4, 3, 2
console.log('start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
console.log('end');
// 输出:start, end, setTimeout
console.log('1');
Promise.resolve().then(() => {
console.log('2');
});
queueMicrotask(() => {
console.log('3');
});
console.log('4');
// 输出:1, 4, 2, 3
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('3');
});
}, 0);
Promise.resolve().then(() => {
console.log('4');
setTimeout(() => {
console.log('5');
}, 0);
});
console.log('6');
// 输出顺序:1, 6, 4, 2, 3, 5
// 解释:
// 1. 同步代码:1, 6
// 2. 微任务:4(执行时又添加了 setTimeout 宏任务)
// 3. 宏任务:2(执行时又添加了 Promise 微任务)
// 4. 微任务:3
// 5. 宏任务:5
async/await 基于 Promise,await 后面的代码会被包装成微任务:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
// 输出顺序:
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout
Node.js 的事件循环包含多个阶段:
// Node.js 中的执行顺序
console.log('1');
setTimeout(() => console.log('2'), 0);
setImmediate(() => console.log('3'));
process.nextTick(() => console.log('4'));
Promise.resolve().then(() => console.log('5'));
console.log('6');
// 输出:1, 6, 4, 5, 2, 3
// process.nextTick 优先级最高
// 将耗时操作分解为多个微任务
function processLargeArray(array) {
return new Promise(resolve => {
let index = 0;
function processChunk() {
const chunkSize = 1000;
const end = Math.min(index + chunkSize, array.length);
while (index < end) {
// 处理数据
processItem(array[index]);
index++;
}
if (index < array.length) {
// 使用微任务继续处理
Promise.resolve().then(processChunk);
} else {
resolve();
}
}
processChunk();
});
}
// 使用微任务确保高优先级
function highPriorityTask() {
Promise.resolve().then(() => {
console.log('高优先级任务');
});
}
function lowPriorityTask() {
setTimeout(() => {
console.log('低优先级任务');
}, 0);
}
highPriorityTask();
lowPriorityTask();
// 高优先级任务先执行
let updateQueue = [];
let isUpdating = false;
function scheduleUpdate(update) {
updateQueue.push(update);
if (!isUpdating) {
isUpdating = true;
Promise.resolve().then(() => {
// 批量处理更新
updateQueue.forEach(update => update());
updateQueue = [];
isUpdating = false;
});
}
}
// 不好的做法
function badLoop() {
for (let i = 0; i < 10000000; i++) {
// 阻塞主线程
}
}
// 好的做法:使用异步
async function goodLoop() {
for (let i = 0; i < 10000000; i++) {
if (i % 1000 === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
// DOM 更新在微任务之后
button.addEventListener('click', () => {
Promise.resolve().then(() => {
console.log('微任务');
});
console.log('同步');
});
// 输出:同步, 微任务
// DOM 更新发生在微任务之后