一、为什么需要 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');/* 输出顺序:StartEndPromise 1Promise 2Microtask in PromiseTimeout*/
七、常见问题
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.jsself.onmessage = (e) => {const result = heavyCalculation(e.data);self.postMessage(result);};
理解 Event Loop 的运行机制所带来的优势:
-
1.编写更高效的异步代码
-
2.避免常见性能陷阱
-
3.实现流畅的交互体验
-
4.更好地处理复杂任务调度
![]() |
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |




浙公网安备 33010602011771号