news 2026/2/12 18:29:32

JavaScript 事件循环机制详解及项目中的应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript 事件循环机制详解及项目中的应用

第一部分:基础概念

1. JavaScript 执行环境

JavaScript 是单线程的,这意味着它一次只能执行一个任务。为了处理异步操作,JavaScript 使用事件循环机制。

2. 核心组件

  • 调用栈(Call Stack):执行同步代码的地方
  • 任务队列(Task Queue):分为宏任务队列和微任务队列
  • 事件循环(Event Loop):协调调用栈和任务队列的机制

第二部分:举例详细解析

console.log('1. 同步任务开始');setTimeout(()=>{console.log('2. setTimeout 回调');},0);Promise.resolve().then(()=>{console.log('3. Promise.then 回调');});console.log('4. 同步任务结束');

执行步骤分析:

第1步:同步任务执行
  1. console.log('1. 同步任务开始')压入调用栈,立即执行,输出1
  2. setTimeout压入调用栈,Web API 开始计时(0ms),回调函数放入宏任务队列
  3. Promise.resolve().then()压入调用栈,.then()的回调函数放入微任务队列
  4. console.log('4. 同步任务结束')压入调用栈,立即执行,输出4

此时状态:

  • 调用栈:空
  • 微任务队列[Promise.then回调]
  • 宏任务队列[setTimeout回调]
第2步:事件循环检查
  1. 调用栈为空,事件循环开始工作
  2. 优先检查微任务队列,发现有一个任务
  3. 执行微任务:console.log('3. Promise.then 回调'),输出3
  4. 微任务队列清空
第3步:继续事件循环
  1. 微任务队列为空,现在检查宏任务队列
  2. 执行宏任务:setTimeout回调,输出2
  3. 宏任务队列清空

最终输出顺序:1 4 3 2

console.log('script start')asyncfunctionasync1(){awaitasync2()console.log('async1 end')}asyncfunctionasync2(){console.log('async2 end')}async1()setTimeout(function(){console.log('setTimeout')},0)newPromise(resolve=>{console.log('Promise')resolve()}).then(function(){console.log('Promise1')})

关键概念:async/await

  • async函数总是返回一个 Promise
  • await会暂停 async 函数的执行,直到 Promise 解决
  • await后面的代码相当于放在.then()中,属于微任务

执行步骤分析:

第1步:同步任务执行
  1. console.log('script start')→ 输出script start

  2. 定义函数async1async2(不执行)

  3. 调用async1()

    • 进入async1,遇到await async2()
    • 调用async2()console.log('async2 end')→ 输出async2 end
    • await暂停执行,console.log('async1 end')被包装成微任务放入微任务队列
  4. setTimeout→ 回调函数放入宏任务队列

  5. 执行new Promise

    • console.log('Promise')是同步代码 → 输出Promise
    • resolve()执行,.then()的回调放入微任务队列

此时状态:

  • 调用栈:空
  • 微任务队列[async1 end, Promise1](注意顺序!)
  • 宏任务队列[setTimeout回调]
第2步:事件循环检查微任务
  1. 调用栈为空,执行微任务

  2. 按入队顺序执行微任务:

    • 第一个微任务:console.log('async1 end')→ 输出async1 end
    • 第二个微任务:console.log('Promise1')→ 输出Promise1
  3. 微任务队列清空

第3步:执行宏任务
  1. 执行setTimeout回调 → 输出setTimeout

最终输出顺序:script start → async2 end → Promise → async1 end → Promise1 → setTimeout

那么到此,应该是可以理解到事件循环的感觉了,那接下来我们就开始看看事件循环的完整逻辑

1. 任务分类

宏任务(Macrotasks)
  • setTimeoutsetInterval
  • setImmediate(Node.js)
  • requestAnimationFrame(浏览器)
  • I/O 操作
  • UI 渲染(浏览器)
  • 主线程的 script 标签内容
微任务(Microtasks)
  • Promise.then().catch().finally()
  • process.nextTick()(Node.js,优先级最高)
  • MutationObserver(浏览器)
  • queueMicrotask()
  • async/await的后续代码

2. 事件循环执行顺序

1. 执行一个宏任务(script标签内容) 2. 执行过程中遇到异步任务: - 宏任务 → 放入宏任务队列 - 微任务 → 放入微任务队列 3. 当前宏任务执行完毕 4. 检查微任务队列,依次执行所有微任务 5. 如有必要,进行UI渲染 6. 从宏任务队列取出下一个宏任务执行 7. 回到步骤3,形成循环

3. 重要规则

规则1:微任务优先
  • 每执行完一个宏任务,都要清空所有微任务
  • 微任务执行期间产生的新微任务会加入当前队列,并在本次循环中执行
规则2:async/await 转化

javascript

asyncfunctionexample(){awaitfoo()// 相当于 Promise.resolve(foo()).then(...)console.log('A')// 这部分在微任务队列中}
规则3:多个任务队列
  • 宏任务可能有多个来源(定时器、I/O等),有各自的队列
  • 微任务只有一个队列,按入队顺序执行

在举例理解一下

javascript

// 测试微任务嵌套Promise.resolve().then(()=>{console.log('微任务1');Promise.resolve().then(()=>{console.log('微任务中的微任务');});}).then(()=>{console.log('微任务2');});// 输出顺序:微任务1 → 微任务中的微任务 → 微任务2

javascript

// 测试多个宏任务setTimeout(()=>console.log('宏任务1'),10);Promise.resolve().then(()=>console.log('微任务1'));setTimeout(()=>{console.log('宏任务2');Promise.resolve().then(()=>console.log('宏任务2中的微任务'));},1);Promise.resolve().then(()=>console.log('微任务2'));setTimeout(()=>{console.log('宏任务3');Promise.resolve().then(()=>console.log('宏任务3中的微任务'));},0);结果: 微任务1微任务2宏任务3宏任务3中的微任务 宏任务1宏任务2宏任务2中的微任务 为什么呢?聪明的你已经会了 一开始 微任务 放入 微任务1, 微任务2;然后宏任务放入 宏任务3这个时候, 计时器还没有到底100ms的时候, 打印微任务1、微任务2;然后微任务清空,开始 宏任务3, 放入微任务 宏任务3中的微任务,然后打印宏任务3中的微任务; 然后计时器到了,打印宏任务1、宏任务2、放入微任务, 打印宏任务2中的微任务;大概就是这种感觉

总结

  1. 同步任务立即执行
  2. 微任务宏任务优先级高
  3. 每个宏任务执行后,都要清空所有微任务
  4. async/await本质是 Promise 的语法糖,await后面的代码是微任务
  5. 事件循环确保了 JavaScript 的单线程能够处理异步操作
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/5 23:30:28

40、敏捷开发相关指标与实践解析

敏捷开发相关指标与实践解析 1. Sidky敏捷测量指数(SAMI)反馈 为了收集关于Sidky敏捷测量指数(SAMI)的反馈,向28位敏捷社区成员展示了SAMI,并通过90分钟的个人访谈(单独或分组)获取反馈,访谈包括SAMI的介绍、讨论和填写问卷环节。问卷主要关注SAMI的全面性、实用性、…

作者头像 李华
网站建设 2026/2/12 11:18:37

ComfyUI与玻璃艺术结合:光影效果AI模拟实验

ComfyUI与玻璃艺术结合:光影效果AI模拟实验 在数字艺术创作的前沿,一个日益凸显的挑战是:如何让AI不仅“画得像”,还能“理解材质”?尤其是在表现玻璃这种兼具透明、折射、反射和辉光特性的复杂介质时,传统…

作者头像 李华
网站建设 2026/2/8 16:54:29

ComfyUI工作流依赖管理机制设计:确保可复现性

ComfyUI工作流依赖管理机制设计:确保可复现性 在生成式AI迅速渗透内容创作领域的今天,一个看似简单的问题却困扰着无数开发者与创作者:为什么同样的提示词,在不同时间或不同电脑上生成的图像却不一致?更令人头疼的是&a…

作者头像 李华
网站建设 2026/2/10 12:16:35

腾讯Hunyuan-1.8B-Instruct-AWQ-Int4开源:轻量化大模型引领边缘智能革命

2025年,中国人工智能市场迎来爆发式增长,整体规模突破7470亿元大关,其中生成式AI业务贡献了41%的同比增幅。然而,繁荣背后隐藏着行业痛点:企业级AI应用落地仍面临"三重壁垒"——动辄千万级的部署成本、专业技…

作者头像 李华
网站建设 2026/2/6 14:18:54

1.4 实战项目:用AI从零构建项目管理工具原型

1.4 实战项目:用AI从零构建项目管理工具原型 经过前三节课的学习,我们已经掌握了AI编程工具的基本概念、主流大语言模型的特点以及开发环境的搭建。现在是时候将这些知识付诸实践了!本节课我们将使用AI工具从零开始构建一个项目管理工具原型,亲身体验AI如何显著提升我们的…

作者头像 李华