前言
🍊 你想听的故事
0元购的秒杀bug是怎么炼成的?
场景还原:
某电商大促活动,程序员小明用setTimeout(fn,0)
实现倒计时抢购。结果用户疯狂点击抢购按钮,页面直接卡死。
真相:小明不知道setTimeout
的延迟参数只是最低等待时间,回调会被塞进宏任务队列排队执行,而同步代码阻塞导致回调延迟执行,最终引发雪崩效应。
🐣闪亮主角
javascript事件循环机制
大家好,我是JavaDog程序狗。今天给大家分享:
事件循环机制是 JavaScript 异步编程的核心,通过调用栈、任务队列和事件循环的协同工作,实现了异步任务的处理。理解事件循环机制对于编写高效、无阻塞的 JavaScript 代码至关重要,同时也是面试中常见的考点。
你能理清这段代码的执行顺序吗?
快来自己跑一下代码,挑战一下自己的软肋吧
console.log('start');
const interval = setInterval(() => {
console.log('interval');
Promise.resolve().then(() => console.log('interval microtask'));
}, 0);
setTimeout(() => {
console.log('timeout');
clearInterval(interval);
}, 100);
Promise.resolve().then(() => console.log('promise1'));
🍉事故现场
一场价值10K的翻车对话
面试官:说说JS事件循环机制?
候选人(自信满满):简单!就是先执行同步代码,再处理异步任务呗~
面试官(微笑):那这段代码输出顺序是啥?
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
候选人(冷汗直冒):1、4、2、3?
面试官(死亡凝视):回去等通知吧…
真相:正确答案是 1 → 4 → 3 → 2!
👉 狗哥锐评:不懂事件循环的程序员,就像外卖小哥不看导航——迟早送错单!
正文
🚀 1.JS事件循环的本质:食堂大妈打菜模型
1. 单线程的宿命
JS天生是单线程(参考),就像食堂只有一个打菜窗口。如果大妈(主线程)遇到耗时操作(比如等红烧肉炖熟),队伍就卡死了!
2. 核心三件套
- 调用栈(Call Stack):大妈手里的餐盘,同步代码直接装盘
- 任务队列(Task Queue):排队的学生们,异步任务按类型分窗口(宏任务/微任务)
- 事件循环(Event Loop):大妈的打菜循环:
1. 清空当前餐盘(同步代码)
2. 优先给学生发甜点(执行所有微任务)
3. 再给下一个主食窗口发饭(执行一个宏任务)
4. 重复以上步骤
🔥 2.血泪三连击:80%程序员踩过的坑
1. 微任务插队惨案
setTimeout(() => console.log('宏任务'));
Promise.resolve().then(() => console.log('微任务'));
// 输出:微任务 → 宏任务
狗哥锐评:微任务就像VIP会员,永远比宏任务优先!
2. setTimeout(0) 的谎言
你以为setTimeout(fn, 0)
会立即执行?Naive!实际至少要等4ms(浏览器规范),比如:
console.log('开始');
setTimeout(() => console.log('超时'), 0);
console.log('结束');
// 输出:开始 → 结束 → 超时
3. Node.js vs 浏览器
场景 | 浏览器 | Node.js |
---|---|---|
微任务优先级 | Promise > MutationObserver | process.nextTick > Promise |
宏任务阶段 | 无明确阶段 | 分timers/poll/check等6个阶段 |
🥒3.防暴毙指南:事件循环的正确姿势
1. 宏任务 vs 微任务速记
类型 | 举例 |
---|---|
宏任务(主食) | setTimeout、setInterval、I/O操作 |
微任务(甜点) | Promise.then、process.nextTick |
2. 面试题降维打击
例题:以下代码输出顺序是?
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(执行时新增宏任务5)
- 宏任务队列:2(执行时新增微任务3)
- 下一轮微任务:3
- 最后宏任务:5
👉 答案:1 → 6 → 4 → 2 → 3 → 5
🌟 4.终极总结:四句真言保平安
*事件循环就像渣男——永远先处理新欢(微任务),再回头找旧爱(宏任务)
- 同步优先清空栈
- 微任务比宏任务快
- Node阶段记分明
- 嵌套调用看队列
结尾
🍈猜你想问
如何与狗哥联系进行探讨
1. 关注公众号【JavaDog程序狗】
公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过360+个小伙伴啦!!!
2.踩踩狗哥博客
里面有狗哥的私密联系方式呦 😘
大家可以在里面留言,随意发挥,有问必答
🍯猜你喜欢
文章推荐
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!