前端人搞不清任务队列?3分钟看懂事件循环里的宏任务微任务(附避


前端人搞不清任务队列?3分钟看懂事件循环里的宏任务微任务(附避

  • 前端人搞不清任务队列?3分钟看懂事件循环里的宏任务微任务(附避坑指南)
    • 为啥我写的 setTimeout 总是比 Promise 慢半拍?
    • 事件循环听着高大上,其实它就是个“打工人调度器”
    • 宏任务家族都有谁:script、setTimeout、setInterval、I/O、UI 渲染…
    • 微任务天团成员:Promise.then、queueMicrotask、MutationObserver、process.nextTick(Node 专属)
    • 宏任务和微任务的执行顺序到底怎么跑?
    • UI 渲染到底在哪个环节发生?requestAnimationFrame 又插在哪?
    • 经典的“我以为先执行”翻车现场
      • 1. setTimeout(fn, 0) 真的是立刻执行吗?
      • 2. Promise 构造函数是同步的,.then 才是异步的
      • 3. Vue 的 nextTick 到底用了啥?
    • 遇到诡异时序问题怎么排查?
      • 1. console.log 大法好,但得打在哪一层
      • 2. performance.mark + measure 精准定位
      • 3. Chrome DevTools Performance 面板
    • 写代码时怎么利用任务机制优化体验?
      • 1. 把耗时计算拆到多个宏任务,避免页面卡死
      • 2. 用 queueMicrotask 替代 Promise.resolve().then() 更语义化
      • 3. 想在 DOM 更新后立刻操作?别乱用 setTimeout,试试 nextTick 或 rAF
    • 防抖节流别只盯着时间,结合任务类型能更精准控制
    • 最后唠一句:任务队列不是背八股文,是理解 JS 的呼吸节奏

前端人搞不清任务队列?3分钟看懂事件循环里的宏任务微任务(附避坑指南)

友情提示:本文全程口语化,代码管够,吐槽密集,建议收藏后对着控制台边敲边骂,效果更佳。


为啥我写的 setTimeout 总是比 Promise 慢半拍?

先甩一段“灵魂拷问”代码,欢迎对号入座:

console.log('start');setTimeout(()=>console.log('timeout'),0);Promise.resolve().then(()=>console.log('promise'));console.log('end');

跑出来的顺序永远是:

start end promise timeout

是不是瞬间怀疑人生:我写的 0 毫秒延时呢?Promise 凭啥插队?
别急着砸键盘,这就是宏任务(macrotask)和微任务(microtask)的“排班表”在作怪。
一句话:微任务就是 VIP 通道,宏任务是普通安检口——VIP 没走完,后面经济舱只能干瞪眼。


事件循环听着高大上,其实它就是个“打工人调度器”

JS 是单线程,像一家只有一名咖啡师的星巴克。
顾客(任务)排长队,咖啡师(主线程)一次只能做一杯。
但店里为了“用户体验”,给任务分了俩队:

  • 宏任务队列:今天必须做完,但不差这几秒;
  • 微任务队列:老板亲戚,不做就投诉。

咖啡师流程(事件循环伪代码):

while(queue.waitForCustomer()){constmacroTask=queue.getMacroTask();// 只取一个macroTask.run();// 做完这一单letmicroTask;while(microTask=queue.getMicroTask()){// 清空前,别下班microTask.run();}if(shouldRender())render();// 每轮宏任务后可能刷帧}

看懂了没?一次事件循环 = 1 个宏任务 + 清空所有微任务 + 可能渲染
所以 Promise.then 永远比 setTimeout 早,因为人家在 VIP 队里,setTimeout 还在经济舱排队检票。


宏任务家族都有谁:script、setTimeout、setInterval、I/O、UI 渲染…

先给宏任务“拍全家福”:

来源典型 API备注
脚本<script>第一次同步执行的整段代码就是宏任务
定时器setTimeout / setInterval最小 4ms 延时(HTML 标准)
I/Ofetch 回来、XHR、文件读写网络线程回来再排队
UI用户交互、postMessage浏览器要响应点击、输入
渲染requestAnimationFrame在宏任务后、渲染前插一脚

代码感受下“宏任务众生相”:

// 1. script 本身console.log('script start');// 同步,第一个宏任务// 2. 定时器setTimeout(()=>console.log('setTimeout'),0);// 3. I/Ofetch('/').then(()=>console.log('fetch callback'));// 4. 用户交互button.addEventListener('click',()=>console.log('click'));// 5. UI 渲染requestAnimationFrame(()=>console.log('rAF'));

微任务天团成员:Promise.then、queueMicrotask、MutationObserver、process.nextTick(Node 专属)

微任务人少,但个个都是“关系户”:

来源典型 API备注
Promise.then / .catch / .finally标准微任务
手动queueMicrotask(fn)浏览器新 API,语义更直给
DOMMutationObserver监听 DOM 变动,批量微任务
Nodeprocess.nextTickNode 里比 Promise 还 VIP,比微任务更微

来段“微任务全家桶”:

Promise.resolve().then(()=>console.log('promise'));queueMicrotask(()=>console.log('queueMicrotask'));constobserver=newMutationObserver(()=>console.log('mutation'));observer.observe(document.body,{childList:true});document.body.appendChild(document.createTextNode('hi'));// 触发// Node 环境if(typeofprocess!=='undefined'){process.nextTick(()=>console.log('nextTick'));}

跑在浏览器里,顺序大概率:

promise queueMicrotask mutation

(nextTick 只在 Node 出现,浏览器没有)


宏任务和微任务的执行顺序到底怎么跑?

再上一张“灵魂流程图”——代码版:

console.log('① 同步代码');setTimeout(()=>{console.log('② 宏任务1-setTimeout');Promise.resolve().then(()=>console.log('③ 宏任务1里产生的微任务'));},0);queueMicrotask(()=>{console.log('④ 微任务1-queueMicrotask');setTimeout(()=>console.log('⑤ 微任务里又塞了个宏任务'),0);});Promise.resolve().then(()=>console.log('⑥ 微任务2-promise'));console.log('⑦ 同步代码结束');

控制台输出:

① 同步代码 ⑦ 同步代码结束 ④ 微任务1-queueMicrotask ⑥ 微任务2-promise ② 宏任务1-setTimeout ③ 宏任务1里产生的微任务 ⑤ 微任务里又塞了个宏任务

看懂了没?微任务可以嵌套微任务,但一轮宏任务只能取一个
所以千万别在微任务里写死循环,不然页面直接卡成 PPT:

functionloop(){queueMicrotask(loop);// 无限微任务,浏览器永远走不到下一帧}loop();

UI 渲染到底在哪个环节发生?requestAnimationFrame 又插在哪?

很多人以为“渲染在宏任务之后”,其实更细:
在一次宏任务 + 所有微任务完成后,浏览器会看要不要刷帧
rAF 的回调就插在“宏任务后、渲染前”这个黄金位置。

代码验证:

button.addEventListener('click',()=>{console.log('click 宏任务');Promise.resolve().then(()=>console.log('promise 微任务'));requestAnimationFrame(()=>console.log('rAF'));console.log('click 同步结束');});

点击按钮,输出:

click 宏任务 click 同步结束 promise 微任务 rAF

看到没?rAF 在微任务之后、渲染之前。
所以想在 DOM 更新后、渲染前做点动画,用 rAF 就对了,别傻乎乎 setTimeout。


经典的“我以为先执行”翻车现场

1. setTimeout(fn, 0) 真的是立刻执行吗?

浏览器最小延时 4ms,Node 里 1ms,还要排队。
下面这段代码,timeout 永远最后:

Promise.resolve().then(()=>console.log('then'));setTimeout(()=>console.log('timeout'),0);

2. Promise 构造函数是同步的,.then 才是异步的

newPromise(resolve=>{console.log('promise ctor 同步');resolve();}).then(()=>console.log('promise then 异步'));

输出:

promise ctor 同步 promise then 异步

ctor 里千万别做重计算,否则照样卡线程。

3. Vue 的 nextTick 到底用了啥?

Vue2 兼容写法:

// 优先 Promise.thenif(typeofPromise!=='undefined'){Vue.nextTick=cb=>Promise.resolve().then(cb);}elseif(typeofMutationObserver!=='undefined'){// 降级 MutationObserverconstobserver=newMutationObserver(()=>{// 清空队列});}else{// 再降级 setTimeoutVue.nextTick=cb=>setTimeout(cb,0);}

所以Vue.nextTick 是微任务,放心在里边读 DOM,一定比渲染早。


遇到诡异时序问题怎么排查?

1. console.log 大法好,但得打在哪一层

console.log('=== 宏任务起点 ===');queueMicrotask(()=>console.log('=== 微任务起点 ==='));

给日志加“边框”,一眼看出谁在哪个队列。

2. performance.mark + measure 精准定位

performance.mark('A');setTimeout(()=>{performance.mark('B');performance.measure('A to B','A','B');console.log(performance.getEntriesByName('A to B')[0].duration);},0);

能看到真实延时,而不是“我以为 0ms”。

3. Chrome DevTools Performance 面板

  • 录一段交互;
  • 看 Main 线程火焰图,红色三角就是宏任务紫色小块是微任务
  • 对照帧率,一眼看出谁在掉帧。

写代码时怎么利用任务机制优化体验?

1. 把耗时计算拆到多个宏任务,避免页面卡死

constbigArray=newArray(10_000_000).fill(0).map((_,i)=>i);functionchunk(arr,size=1000){leti=0;functiondoChunk(){constend=Math.min(i+size,arr.length);for(;i<end;i++){// 重计算arr[i]=arr[i]**2;}if(i<arr.length){setTimeout(doChunk,0);// 让出主线程,宏任务续命}}doChunk();}chunk(bigArray);

每 1000 条让一次座,页面还能滚动。

2. 用 queueMicrotask 替代 Promise.resolve().then() 更语义化

// 以前Promise.resolve().then(()=>console.log('next'));// 现在queueMicrotask(()=>console.log('next'));

少了创建 Promise 对象的开销,代码更直给。

3. 想在 DOM 更新后立刻操作?别乱用 setTimeout,试试 nextTick 或 rAF

// Vue 场景this.msg='新消息';this.$nextTick(()=>{// DOM 已更新,可以安心量高度console.log(this.$refs.box.scrollHeight);});

原生场景:

requestAnimationFrame(()=>{// 渲染前最后一站console.log('DOM 马上要刷了');});

防抖节流别只盯着时间,结合任务类型能更精准控制

传统节流:

functionthrottle(fn,wait){letlast=0;returnfunction(...args){constnow=Date.now();if(now-last>wait){last=now;fn.apply(this,args);}};}

但高刷屏幕 120Hz,16ms 一帧,定时器最小 4ms,可能一次刷两帧
用 rAF 做“帧同步节流”更丝滑:

functionrafThrottle(fn){letlocked=false;returnfunction(...args){if(locked)return;locked=true;requestAnimationFrame(()=>{fn.apply(this,args);locked=false;});};}

无论 60Hz 还是 120Hz,都一帧只跑一次,不掉帧、不浪费。


最后唠一句:任务队列不是背八股文,是理解 JS 的呼吸节奏

写前端就像打鼓,宏任务是“咚”,微任务是“哒”,渲染是“次”。
鼓点乱了,用户就觉得卡;节奏对了,页面才能跟着心跳走。
下回再看到 setTimeout 被 Promise 插队,别骂娘——泡杯茶,打开控制台,对着 event loop 的鼓点敲代码,你就是乐队指挥。

(全文完,键盘已冒烟,我去加散热硅脂了。)

欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!


专栏系列(点击解锁)学习路线(点击解锁)知识定位
《微信小程序相关博客》持续更新中~结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等
《AIGC相关博客》持续更新中~AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结
《HTML网站开发相关》《前端基础入门三大核心之html相关博客》前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识
《前端基础入门三大核心之JS相关博客》前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。
通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心
《前端基础入门三大核心之CSS相关博客》介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页
《canvas绘图相关博客》Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化
《Vue实战相关博客》持续更新中~详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅
《python相关博客》持续更新中~Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具
《sql数据库相关博客》持续更新中~SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能
《算法系列相关博客》持续更新中~算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维
《IT信息技术相关博客》持续更新中~作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识
《信息化人员基础技能知识相关博客》无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方
《信息化技能面试宝典相关博客》涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面
《前端开发习惯与小技巧相关博客》持续更新中~罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等
《photoshop相关博客》持续更新中~基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结
日常开发&办公&生产【实用工具】分享相关博客》持续更新中~分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具

吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1138322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3分钟掌握Windows UEFI启动画面定制:让你的开机界面与众不同

3分钟掌握Windows UEFI启动画面定制&#xff1a;让你的开机界面与众不同 【免费下载链接】HackBGRT Windows boot logo changer for UEFI systems 项目地址: https://gitcode.com/gh_mirrors/ha/HackBGRT 想要轻松修改Windows启动画面&#xff0c;实现真正的个性化开机体…

微信社交关系智能检测技术解析

微信社交关系智能检测技术解析 【免费下载链接】WechatRealFriends 微信好友关系一键检测&#xff0c;基于微信ipad协议&#xff0c;看看有没有朋友偷偷删掉或者拉黑你 项目地址: https://gitcode.com/gh_mirrors/we/WechatRealFriends 在数字化社交时代&#xff0c;微信…

如何快速解决微信单向好友问题:完整操作指南

如何快速解决微信单向好友问题&#xff1a;完整操作指南 【免费下载链接】WechatRealFriends 微信好友关系一键检测&#xff0c;基于微信ipad协议&#xff0c;看看有没有朋友偷偷删掉或者拉黑你 项目地址: https://gitcode.com/gh_mirrors/we/WechatRealFriends 在日常社…

Qwen3-VL多语言OCR:32种语言识别对比

Qwen3-VL多语言OCR&#xff1a;32种语言识别对比 1. 引言&#xff1a;为何需要多语言OCR能力&#xff1f; 随着全球化业务的扩展和跨语言内容的爆炸式增长&#xff0c;传统OCR技术在面对多语种混合、低质量图像或复杂排版时逐渐暴露出局限性。尤其是在跨境电商、国际文档处理…

VoiceFixer音频修复终极指南:三步让受损声音重获新生

VoiceFixer音频修复终极指南&#xff1a;三步让受损声音重获新生 【免费下载链接】voicefixer General Speech Restoration 项目地址: https://gitcode.com/gh_mirrors/vo/voicefixer 你是否曾为那些被噪音淹没的珍贵录音而苦恼&#xff1f;那些承载着重要记忆的语音文件…

Qwen2.5-7B指令调优:提升模型响应质量的方法

Qwen2.5-7B指令调优&#xff1a;提升模型响应质量的方法 1. 技术背景与问题提出 随着大语言模型在实际业务场景中的广泛应用&#xff0c;用户对模型输出的准确性、可控性和结构化能力提出了更高要求。尽管基础预训练模型具备强大的语言理解与生成能力&#xff0c;但在面对复杂…

EdgeRemover终极方案:Windows系统彻底删除Edge的完整指南

EdgeRemover终极方案&#xff1a;Windows系统彻底删除Edge的完整指南 【免费下载链接】EdgeRemover PowerShell script to remove Microsoft Edge in a non-forceful manner. 项目地址: https://gitcode.com/gh_mirrors/ed/EdgeRemover 还在为Microsoft Edge浏览器无法彻…

JetPack SDK中TensorRT配置:Jetson Xavier NX推理加速指南

Jetson Xavier NX推理加速实战&#xff1a;用TensorRT榨干每1TOPS算力你有没有遇到过这样的场景&#xff1f;在Jetson Xavier NX上部署了一个YOLOv5模型&#xff0c;满怀期待地运行起来&#xff0c;结果帧率只有十几FPS——远低于宣传中“90 FPS”的惊人数据。设备风扇狂转&…

LIWC文本分析工具终极指南:从心理学视角解读文本情感

LIWC文本分析工具终极指南&#xff1a;从心理学视角解读文本情感 【免费下载链接】liwc-python Linguistic Inquiry and Word Count (LIWC) analyzer 项目地址: https://gitcode.com/gh_mirrors/li/liwc-python 想要深入挖掘文本背后的心理学奥秘吗&#xff1f;LIWC文本…

仿写文章创作规范指南

仿写文章创作规范指南 【免费下载链接】liwc-python Linguistic Inquiry and Word Count (LIWC) analyzer 项目地址: https://gitcode.com/gh_mirrors/li/liwc-python 请基于提供的参考文章&#xff0c;创作一篇全新的仿写文章。要求保持核心信息准确&#xff0c;但在结…

ModTheSpire终极指南:解锁《杀戮尖塔》无限模组可能

ModTheSpire终极指南&#xff1a;解锁《杀戮尖塔》无限模组可能 【免费下载链接】ModTheSpire External mod loader for Slay The Spire 项目地址: https://gitcode.com/gh_mirrors/mo/ModTheSpire 想要彻底改变你的《杀戮尖塔》游戏体验吗&#xff1f;ModTheSpire作为专…

医学影像三维可视化实战:从入门到精通的完整解决方案

医学影像三维可视化实战&#xff1a;从入门到精通的完整解决方案 【免费下载链接】MRIcroGL v1.2 GLSL volume rendering. Able to view NIfTI, DICOM, MGH, MHD, NRRD, AFNI format images. 项目地址: https://gitcode.com/gh_mirrors/mr/MRIcroGL 您是否曾经面临这样的…

AI音频修复终极指南:让每一段语音重获清晰质感

AI音频修复终极指南&#xff1a;让每一段语音重获清晰质感 【免费下载链接】voicefixer General Speech Restoration 项目地址: https://gitcode.com/gh_mirrors/vo/voicefixer 在现代数字生活中&#xff0c;AI音频修复技术正成为语音增强和噪音消除的重要工具。无论是会…

Qwen2.5-7B部署疑问解答:网页服务无法启动?实战排查教程

Qwen2.5-7B部署疑问解答&#xff1a;网页服务无法启动&#xff1f;实战排查教程 1. 背景与问题引入 1.1 Qwen2.5-7B 模型简介 Qwen2.5 是阿里云最新发布的大型语言模型系列&#xff0c;覆盖从 0.5B 到 720B 的多种参数规模。其中 Qwen2.5-7B 作为中等规模的高性能模型&#x…

nmodbus4类库使用教程:图解说明报文帧结构解析过程

nmodbus4类库使用教程&#xff1a;深入剖析Modbus报文帧解析全过程在工业自动化和物联网系统中&#xff0c;设备间的通信是构建稳定监控与控制体系的基石。作为最广泛使用的工业协议之一&#xff0c;Modbus以其简洁、开放、易于实现的特点&#xff0c;长期占据着PLC、传感器、仪…

DroidCam OBS插件:手机变身高清摄像头的完整指南

DroidCam OBS插件&#xff1a;手机变身高清摄像头的完整指南 【免费下载链接】droidcam-obs-plugin DroidCam OBS Source 项目地址: https://gitcode.com/gh_mirrors/dr/droidcam-obs-plugin 还在为专业直播设备的高昂价格而烦恼&#xff1f;想要获得高清直播效果却预算…

Qwen2.5-7B镜像优势解析:为何能实现快速网页推理服务?

Qwen2.5-7B镜像优势解析&#xff1a;为何能实现快速网页推理服务&#xff1f; 1. 技术背景与核心挑战 随着大语言模型&#xff08;LLM&#xff09;在自然语言理解、代码生成、多轮对话等场景的广泛应用&#xff0c;如何将高性能模型高效部署为低延迟、高并发的网页推理服务&am…

从零排查GPU共享库错误:libcudart.so.11.0 找不到的实战案例

一次真实的GPU共享库排查之旅&#xff1a;当libcudart.so.11.0找不到时&#xff0c;我们到底该查什么&#xff1f;你有没有在深夜跑模型时&#xff0c;突然被这样一行红色错误拦住去路&#xff1a;ImportError: libcudart.so.11.0: cannot open shared object file: No such fi…

OpenCore-Configurator终极指南:黑苹果配置的革命性突破

OpenCore-Configurator终极指南&#xff1a;黑苹果配置的革命性突破 【免费下载链接】OpenCore-Configurator A configurator for the OpenCore Bootloader 项目地址: https://gitcode.com/gh_mirrors/op/OpenCore-Configurator 你是否曾为黑苹果配置的复杂性而苦恼&…

3步解锁闲置电视盒子新技能:从安卓TV到全能Linux服务器

3步解锁闲置电视盒子新技能&#xff1a;从安卓TV到全能Linux服务器 【免费下载链接】amlogic-s9xxx-armbian amlogic-s9xxx-armbian: 该项目提供了为Amlogic、Rockchip和Allwinner盒子构建的Armbian系统镜像&#xff0c;支持多种设备&#xff0c;允许用户将安卓TV系统更换为功能…