当前位置: 首页 > news >正文

Event Loop事件循环

1. 同步和异步

JavaScript是一种单线程语言,所有任务都在一个线程上完成。一旦遇到大量任务或者遇到一个耗时的任务,比如加载一个高清图片,网页就会出现"假死",因为JavaScript停不下来,也就无法响应用户的行为。为了防止主线程的阻塞,JavaScript 有了 同步 和 异步 的概念。

同步:调用一旦开始,调用者必须等待方法执行完成,才能继续执行后续方法。
异步:方法一旦开始,立即返回,调用者无需等待其中方法执行完成,就可以继续执行后续方法。

2. 事件循环机制 Event Loop

事件循环(Event Loop)是 JavaScript 运行时(浏览器/Node.js)用于协调同步代码、异步回调、页面渲染的一套调度机制。它决定了代码执行的顺序和时机

2.1 执行顺序

  1. 先执行一个宏任务也就是整体script里的代码
  2. 遇到同步任务立即执行
  3. 遇到宏任务则将宏任务放入宏任务队列中
  4. 遇到微任务则将微任务放入微任务队列中
  5. 当所有同步代码执行完毕后,再将微任务从队列中调入主线程执行直至微任务队列清空(哪怕执行微任务时又产生了新的微任务,也会在本轮继续清空,直到微任务队列为空,才会取下一个宏任务。)
  6. 检查是否需要渲染页面,如果需要渲染 → 执行渲染流程(样式计算 → 布局 → 绘制);如果不需要 → 跳过
  7. 再从宏任务队列中取出一个执行
  8. 一直循环直至所有任务执行完毕

2.2 宏任务

宏任务来源说明示例
整个script标签的执行事件循环启动后取出的第一个宏任务,所有全局同步代码都是它的执行体页面加载时执行的JS代码
setTimeout/setInterval回调定时器延迟时间达到后,回调被加入宏任务队列setTimeout(()=>{}, 0)
UI交互事件回调用户操作触发后,回调加入宏任务队列click/keydown/mousemove/touchstart等
I/O完成回调浏览器底层I/O操作完成后触发的回调(注意:不是JS回调本身)fetch/XHR网络请求完成、FileReader文件读取完成、IndexedDB操作完成
postMessage回调跨窗口/跨Worker通信时,消息被接收后触发的回调window.postMessage(data)的onmessage回调
MessageChannel回调通过MessageChannel创建的端口发送消息后,接收端的onmessage回调const channel = new MessageChannel(); channel.port1.onmessage = () => {}
requestAnimationFrame回调浏览器下一次渲染前执行的回调,属于宏任务,但优先级高于普通宏任务做动画时常用的API
requestIdleCallback回调浏览器空闲时期执行的回调,优先级低于普通宏任务,只有主线程无任务时才会执行执行低优先级任务(如日志上报、预加载)

2.2 微任务

微任务来源说明你熟悉的场景
Promise.prototype.then/catch/finally回调最常见的微任务,Promise状态变更后触发你写异步逻辑最常用的API
await后面的代码await xx等价于 Promise.resolve(xx).then(()=>{}),await后的代码就是then的回调,属于微任务await后面的语句不会阻塞同步代码
queueMicrotask回调ES2020新增的API,专门用于创建微任务,比Promise.then更纯粹(没有Promise状态转换的开销)Vue3的nextTick底层就用它兜底
MutationObserver回调监听DOM变化触发的回调,DOM变更后、下一个宏任务前执行Vue2的nextTick在兼容环境下用它实现
IntersectionObserver回调监听元素可见性变化触发的回调,属于微任务图片懒加载、曝光埋点的核心API

2.4 例题

setTimeout(function(){ console.log('1'); }); new Promise(function(resolve){ console.log('2'); resolve(); }).then(function(){ console.log('3'); }); console.log('4'); //输出顺序:2 4 3 1

解释:

  1. 遇到setTimout,异步宏任务,放入宏任务队列中
  2. 遇到new Promise,Promise在实例化的过程中所执行的代码都是同步进行的,所以输出2
  3. 而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
  4. 遇到同步任务console.log(‘4’);输出4;主线程中同步任务执行完
  5. 从微任务队列中取出任务到主线程中,输出3,微任务队列为空
  6. 从宏任务队列中取出任务到主线程中,输出1,宏任务队列为空,结束
setTimeout(()=>{ new Promise(resolve =>{ resolve(); }).then(()=>{ console.log('test'); }); console.log(4); }); new Promise(resolve => { resolve(); console.log(1) }).then( () => { console.log(3); Promise.resolve().then(() => { console.log('before timeout'); }).then(() => { Promise.resolve().then(() => { console.log('also before timeout') }) }) }) console.log(2); //输出:1 2 3 before timeout also before timeout 4 test

解释:

  1. 遇到setTimeout,异步宏任务,将() => {console.log(4)}放入宏任务队列中
  2. 遇到new Promise,Promise在实例化的过程中所执行的代码都是同步进行的,所以输出1;
  3. 而Promise.then中注册的回调才是异步执行的,将其放入微任务队列中
  4. 遇到同步任务console.log(2),输出2;主线程中同步任务执行完
  5. 从微任务队列中取出任务到主线程中,输出3,此微任务中又有微任务,Promise.resolve().then(微任务a).then(微任务b),将其依次放入微任务队列中;
  6. 从微任务队列中取出任务a到主线程中,输出 before timeout;
  7. 从微任务队列中取出任务b到主线程中,任务b又注册了一个微任务c,放入微任务队列中;
  8. 从微任务队列中取出任务c到主线程中,输出 also before timeout;微任务队列为空
  9. 从宏任务队列中取出任务到主线程,此任务中注册了一个微任务d,将其放入微任务队列中,接下来遇到输出4,宏任务队列为空
  10. 从微任务队列中取出任务d到主线程 ,输出test,微任务队列为空,结束
http://www.cnnetsun.cn/news/3564039.html

相关文章:

  • AI4R核心功能大揭秘:从分类器到Transformer的全方位解析
  • 计算机毕业设计之网上书店系统
  • java汉诺塔(递归实现)
  • ubuntu-post-install完全指南:让你的Ubuntu系统初始化效率提升10倍的终极脚本集
  • 一款基于车载协议的socket通讯工具
  • 面向对象的思考
  • next-data-hooks性能优化:深入理解代码消除机制
  • TCP三次握手:为什么需要三次,每一次握手的作用是什么
  • 供需双增叠加政策迭代,动力电池行业开启高质量竞争新周期
  • [Android] az录屏大师 -1080p高清录制
  • 386 · Longest Substring with At Most K Distinct Characters最多有k个不同字符的最长子字符串(滑动窗口)
  • 不群发、不买链接、不写客座文章——我只靠一条原创数据拿到了200条外链
  • 第三章 镜像仓库总结-001篇
  • smsBomb配置完全指南:从配置文件到API密钥的详细设置
  • 运维工程师转型渗透测试:思维重塑与6-9个月实战路线图
  • GameVault多平台支持:Windows与Linux游戏兼容性终极指南 [特殊字符]
  • Claude Code实战避坑指南:7大核心痛点与解决方案
  • 【WorkBuddy从入门到精通实战教程】使用手册 第 5 章 WorkBuddy加载一个真正用得上的 Skill
  • shell数组的一些总结
  • 告别文献焦虑✅Okbiye千万文献库+学术翻译!搞定论文参考文献、外文研读全流程
  • 递归对抗拓扑学(RAT)主纤维丛建模认知冲突完整框架(世毫九实验室原创研究)
  • FossFLOW架构图工具深度解析:如何构建专业级等距可视化系统
  • HarmonyOS应用开发实战:小事记 - 网络请求封装:请求/响应拦截器、超时重试、取消请求
  • M12 B-Code(B编码)5芯连接器完整解析
  • SpringBatch批处理实战:架构解析与性能优化
  • 3个策略让cJSON在工业控制系统中实现零内存泄漏的JSON处理
  • HDMI矩阵与EDID管理在无纸化会议中的应用
  • 终极指南:Magisk技术架构深度解析与性能优化策略
  • 2026横评:3大宁波周末语文小升初机构全面评测
  • 百考通一键生成:AI赋能开题报告,让学术研究起步更高效