一、为什么需要 Event Loop?
JavaScript 是 单线程语言,意味着它一次只能执行一个任务。但浏览器中需要处理大量异步操作(如网络请求、定时器、用户事件),如果让主线程等待这些操作完成,会导致页面“卡死”。Event Loop(事件循环) 的机制让 JS 在单线程下也能实现非阻塞异步执行。通过 Event Loop 机制实现了:
- 1.非阻塞 I/O 操作
- 2.异步任务处理
- 3.高并发处理能力
二、核心架构图解
┌───────────────────────┐
│ Call Stack │ ← 同步代码执行
└──────────┬────────────┘
│
│
┌──────────▼────────────┐
│ Web APIs/DOM APIs │ ← 定时器/事件监听/网络请求
└──────────┬────────────┘
│
│
┌──────────▼────────────┐
│ Task Queue (Macro) │ ← setTimeout/setInterval/UI事件
├───────────────────────┤
│ Microtask Queue │ ← Promise/MutationObserver
└──────────┬────────────┘
│
┌──────────▼────────────┐
│ Event Loop │ ← 持续检查队列的调度机制
└───────────────────────┘三、执行顺序规则
- 1.执行同步代码直至调用栈清空
- 2.执行所有微任务(Microtasks)
- 3.执行一个宏任务(Macrotask)
- 4.重复循环
四、代码演示
console.log('1. Script Start');
setTimeout(() => {
console.log('6. setTimeout');
}, 0);
new Promise((resolve) => {
console.log('2. Promise Constructor');
resolve();
})
.then(() => {
console.log('4. Promise Then 1');
})
.then(() => {
console.log('5. Promise Then 2');
});
console.log('3. Script End');
// 输出顺序:
// 1. Script Start
// 2. Promise Constructor
// 3. Script End
// 4. Promise Then 1
// 5. Promise Then 2
// 6. setTimeout五、任务类型分类
任务类型 | 示例 | 优先级 |
微任务(Micro) | Promise.then / queueMicrotask | 高 |
宏任务(Macro) | setTimeout / setInterval | 低 |
渲染任务 | requestAnimationFrame | 特殊 |
六、实战应用
1. 性能优化
// 错误示例:阻塞主线程
function longTask() {
for(let i=0; i<1e7; i++){
// 长时间同步计算
}
}
// 正确做法:分解任务
function chunkedTask() {
let i = 0;
function processChunk() {
while(i < 1e7 && performance.now() - start < 50) {
i++
}
if(i < 1e7) {
setTimeout(processChunk);
}
}
const start = performance.now();
processChunk();
}2. 优先级控制
// 微任务优先处理
button.addEventListener('click', () => {
Promise.resolve().then(() => {
console.log('Microtask handling click');
});
setTimeout(() => {
console.log('Macrotask handling click');
});
});3. 混合任务处理
console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
Promise.resolve()
.then(() => {
console.log('Promise 1');
queueMicrotask(() => console.log('Microtask in Promise'));
})
.then(() => console.log('Promise 2'));
console.log('End');
/* 输出顺序:
Start
End
Promise 1
Promise 2
Microtask in Promise
Timeout
*/七、常见问题
1. 函数节流优化
function throttle(fn, delay) {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if(now - lastCall >= delay) {
fn(...args);
lastCall = now;
} else {
requestAnimationFrame(() => throttle(fn, delay)(...args));
}
};
}2. 竞态条件处理
let controller = new AbortController();
async function fetchData() {
try {
const response = await fetch(url, {
signal: controller.signal
});
// 处理响应
} catch (e) {
if (e.name === 'AbortError') {
console.log('请求已取消');
}
}
}
// 取消前一个请求
function refreshData() {
controller.abort();
controller = new AbortController();
fetchData();
}Web Workers 集成
// 主线程
const worker = new Worker('worker.js');
worker.onmessage = (e) => {
console.log('Received:', e.data);
};
worker.postMessage('Start');
// worker.js
self.onmessage = (e) => {
const result = heavyCalculation(e.data);
self.postMessage(result);
};理解 Event Loop 的运行机制所带来的优势:
- 1.编写更高效的异步代码
- 2.避免常见性能陷阱
- 3.实现流畅的交互体验
- 4.更好地处理复杂任务调度
















