前端事件循环:代码世界的“排队”艺术!
🔥 以龙息淬炼代码,在时光灰烬中重铸技术星河 !
欢迎来到
晷龙烬
的博客小窝✨!
这里记录技术学习点滴,分享实用技巧,偶尔聊聊奇思妙想~原创内容✍️,转载请注明出处~感谢支持❤️!请尊重原创📩!
欢迎在评论区交流🌟!
引言
想象你在食堂打饭:同步任务是立刻能打的菜,异步任务是要等的特色窗口。而 事件循环就是那个维持排队秩序的保安,确保所有人(代码)按规矩吃饭(执行)!但更深入地说,事件循环是 JavaScript 实现异步编程的核心机制,它协调单线程环境下的任务执行,避免阻塞主线程。今天,咱们就掰开揉碎聊聊这事儿,并揭示其底层运作!
一、事件循环是啥?
简单说:JS是单线程的,一次只能干一件事。但网页操作(点击、加载)那么多,咋办?事件循环的妙招就是:
- 同步任务立刻执行(比如
console.log("饿!")
),它们直接进入主线程的调用栈(Call Stack),按顺序运行。 - 异步任务丢进队列:异步任务分为宏任务(Macrotask)和微任务(Microtask),分别进入不同队列。宏任务队列包括
setTimeout
、I/O操作
等;微任务队列包括Promise.th en()
、MutationObserver
等。 - 队列按优先级处理:事件循环不断检查队列,规则是:每执行一个宏任务,必须清空整个微任务队列。微任务像VIP通道,优先级最高,能“插队”宏任务。
💡 关键点:任务分两种队伍,但事件循环有更精细的流程
- 宏任务队(普通窗口):
script整体代码
、setTimeout
、setInterval
、I/O操作
。它们由宿主环境(如浏览器)管理。- 微任务队(VIP窗口):
Promise.th en/catch
、MutationObserver
、process.ne xtTick
(Node.js)。它们由JS引擎直接处理,执行时机更早。
规则:同步代码 → 清空微任务队 → 执行一个宏任务 → 清空微任务队 → 循环… 这确保微任务优先,避免延迟关键更新。
二、看个真实排队案例
console.log("1. 冲进食堂"); // 同步任务,立刻执行
setTimeout(() => {console.log("4. 最后吃炸鸡"); // 宏任务,进普通队
}, 0);
Promise.resolve().then(() => {console.log("3. 先喝奶茶!"); // 微任务,进VIP队
});
console.log("2. 排队中"); // 同步任务,立刻执行
输出顺序:
1. 冲进食堂
2. 排队中
3. 先喝奶茶!
4. 最后吃炸鸡
为啥?深度解析:
- 同步任务先执行:主线程调用栈运行所有同步代码,输出1和2。此时微任务和宏任务已入队。
- 清空微任务队:事件循环检测微任务队列,发现
Promise.th en()
,立即执行输出3。微任务总在同步代码后、宏任务前处理,即使setTimeout(0)
声称“立刻”也需等待。 - 执行一个宏任务:微任务队列空后,事件循环取一个宏任务(这里
setTimeout
),输出4。注意:宏任务执行中可能产生新微任务,但会在本轮清空。
🚨 重点:微任务插队能力超强,但需注意性能影响
微任务的高优先级能提升响应速度,但过度使用(如循环创建微任务)会阻塞渲染,导致页面卡顿。浏览器事件循环中,微任务清空后才会进行UI更新。
三、循环流程与核心组件
事件循环不只队列,还涉及多个部分:
- 调用栈(Call Stack) :执行同步代码的地方,函数调用时入栈,完成时出栈。
- 任务队列(Task Queue) :分宏任务队列和微任务队列,存储待处理的异步回调。
- 渲染引擎(浏览器) :在微任务清空后,可能触发UI渲染,如
requestAnimationFrame
。
完整流程:
- 主线程执行同步代码(调用栈)。
- 清空微任务队列:所有微任务依次执行,新微任务会追加到当前队列尾。
- 执行一个宏任务:从宏任务队列取一个任务运行。
- 循环回第2步:微任务队列再次清空,然后下一个宏任务,如此反复。
口诀:
“同微宏,微宏”
- 同(同步代码)
- 微(清空微任务)
- 宏(执行1个宏任务)
- 微(再次清空微任务)→ 回第3步宏,形成循环!
这比简单“同微宏”更准确,因为每轮宏任务后都需检查微任务。
四、注意事项与扩展
事件循环在浏览器和Node.js中略有差异:
- 浏览器:事件循环与渲染管线耦合。每轮循环可能包括:执行宏任务 → 清空微任务 → UI渲染。频繁微任务会延迟页面更新。
- Node.js:基于libuv库,有额外队列(如
setImmediate
),且process.ne xtTick
优先级高于普通微任务。
实际影响:在异步编程中,优先使用Promise
/async await
(微任务)而非setTimeout
(宏任务),以提升效率。但避免“微任务地狱”,确保代码可维护。
结语
事件循环就像代码世界的交通指挥系统:
- 同步任务是绿灯直行——立即执行。
- 微任务是救护车优先——总在宏任务前清空。
- 宏任务是普通车排队——按序处理,但需让行微任务。
掌握这套规则,复杂代码顺序再也不会懵圈!更深入理解其组件(调用栈、队列)和平台差异,能写出更高效的异步代码。
✨ 动手试试:
在浏览器运行文中的例子,调整setTimeout
和Promise
位置。尝试添加嵌套微任务(如Promise.re solve().then(() => { ... })
),观察如何阻塞渲染!
—— 完 ——
✨ 至此结束 ✨
💡 点赞关注,解锁更多技术干货!
我是 晷龙烬
期待与你的下次相遇~