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

js事件循环机制简介

一、核心思想:为什么需要事件循环?

JavaScript 是一门单线程的编程语言。这意味着它只有一个主线程来处理所有任务。

如果所有任务(比如网络请求、定时器、用户点击)都同步执行,那么只要有一个耗时任务(如一个 5 秒的循环),页面就会卡死,无法进行任何其他操作。

为了解决这个问题,JavaScript 使用了 异步回调 的机制,而事件循环就是管理这些异步任务执行顺序的机制


二、核心组成部分

要理解事件循环,你需要先了解三个关键部分:

  1. 调用栈

    • 这是一个后进先出的数据结构,用于存储函数调用的执行上下文。
    • 同步任务会直接被压入栈中执行。
    • 当函数执行完毕,它会从栈顶被弹出。
  2. Web APIs / 宿主环境

    • 由浏览器(或 Node.js)提供,用于处理异步操作。
    • 当遇到 setTimeout, setInterval, fetch, DOM事件监听, AJAX 等异步代码时,JS 引擎会将这些任务的回调函数交给 Web APIs 去处理,然后继续执行后面的同步代码。
    • Web APIs 在后台执行这些异步操作(如计时、等待网络响应)。
  3. 任务队列

    • 当 Web APIs 完成了一个异步任务(如定时器时间到了、网络请求返回了),它会将这个任务的回调函数放入一个叫做任务队列的地方排队,等待被调用栈执行。
    • 任务队列又细分为两种:
      • 宏任务队列
      • 微任务队列

三、宏任务 vs. 微任务

这是事件循环机制中最关键的区别!

类型常见例子优先级
宏任务setTimeout, setInterval, setImmediate (Node), I/O 操作, UI 渲染, 整体的 script 代码
微任务Promise.then(), Promise.catch(), Promise.finally(), queueMicrotask(), MutationObserver

核心规则:在一次事件循环中,微任务队列拥有比宏任务队列更高的执行优先级。


四、事件循环的运行流程(经典模型)

你可以将事件循环想象成一个永不停止的循环,它一次又一次地执行以下步骤:

  1. 执行全局同步代码(这是一个宏任务)

    • script 标签开始,将所有同步代码压入调用栈执行。
    • 执行过程中,遇到的异步任务会交给 Web APIs,然后继续执行同步代码。
  2. 清空调用栈

    • 当调用栈中的同步任务全部执行完毕,调用栈变空。
  3. 执行所有微任务

    • 事件循环会立即检查微任务队列
    • 将微任务队列里的所有任务(注意:是所有,直到队列清空)依次取出,放入调用栈执行。
    • 如果在执行一个微任务的过程中,又产生了新的微任务,这个新的微任务也会被加入到当前微任务队列的末尾,并在本次循环中被执行。这意味着微任务可以“插队”。
  4. (可选)更新渲染

    • 浏览器可能会在这个时机进行页面的渲染更新。
  5. 取一个宏任务执行

    • 宏任务队列中取出最前面一个任务(注意:是一个),放入调用栈执行。
    • 这个宏任务执行完毕后,调用栈再次清空。
  6. 回到步骤 3

    • 再次检查微任务队列,执行所有微任务…如此循环往复。

五、经典面试题分析

让我们用这个机制来分析一段代码:

console.log('1'); // 同步代码setTimeout(() => {console.log('2'); // 宏任务回调Promise.resolve().then(() => {console.log('3'); // 微任务});
}, 0);Promise.resolve().then(() => {console.log('4'); // 微任务
});console.log('5'); // 同步代码// 输出顺序是:1, 5, 4, 2, 3

执行步骤分解:

  1. 执行全局同步代码(宏任务)

    • 执行 console.log('1'),输出 1
    • 遇到 setTimeout,将其回调函数交给 Web APIs 计时(0ms后到期),然后继续。
    • 遇到 Promise.resolve().then(...),将其回调函数交给 Web APIs,Web APIs 会立即将其放入微任务队列
    • 执行 console.log('5'),输出 5
    • 此时调用栈清空
  2. 执行所有微任务

    • 检查微任务队列,发现里面有 () => { console.log('4') }
    • 执行它,输出 4
    • 微任务队列清空。
  3. 取一个宏任务执行

    • 此时,setTimeout 的计时已到,它的回调 () => { console.log('2'); ... } 被放入了宏任务队列。
    • 事件循环取出这个宏任务执行。
    • 执行 console.log('2'),输出 2
    • 执行 Promise.resolve().then(...),将其回调 () => { console.log('3') } 放入微任务队列
    • 这个宏任务执行完毕,调用栈清空
  4. 再次执行所有微任务

    • 检查微任务队列,发现里面有 () => { console.log('3') }
    • 执行它,输出 3
    • 微任务队列清空。

最终输出:1, 5, 4, 2, 3

总结

  • 同步任务 > 微任务 > 宏任务
  • 调用栈先执行完所有同步代码。
  • 然后清空所有微任务
  • 最后再取一个宏任务执行。
  • 每执行完一个宏任务,都要回头再清空一遍微任务队列。
http://www.dtcms.com/a/542638.html

相关文章:

  • 吕梁建站公司网站建设背景及意义
  • 网站运行速度慢的原因网站广告赚钱怎么做
  • 南通企业建站模板网站版本功能列表
  • 【Leetcodenowcode】代码强化练习(二叉树)
  • 什么样 个人网站 备案2345浏览器免费版
  • 政务类网站建设wordpress关闭rss功能
  • 网站设计培训学校有哪些天元建设集团有限公司建行账号
  • ElasticSearch-ES
  • vps搭建个人网站opencart 构建电子商务网站
  • 网站推广怎么做深圳洲聚网站建设
  • 网站优化要做哪些唯尚广告联盟平台
  • 公路建设查询网站wordpress+重复插件
  • 如何申请个人网站域名360官方网站网址
  • 网站建设要什么软件wordpress 调用目录
  • 云南电子政务网站建设网站建设的误区
  • 大学学院教授委员会制度研究(五)-具体运作
  • 网站没有索引量是什么意思空间怎么做网站
  • ai免费模板网站专业建设网站技术
  • 网站建设和维护采购协议app推广联盟
  • 做网站属于什么费用西安推荐企业网站制作平台
  • 免费空间域名可以做淘宝客网站推广吗摄影作品投稿网站
  • 临沧网站建设ynyue淘宝客网站名
  • 如何做商业网站推广建设网站需要的材料
  • 全屏定时提醒工具
  • 网站建设的设立方式淘宝网官网登录
  • 用百度云服务器做网站帝国后台网站如何设置自动刷新首
  • 盐城网站建设网站制作推广wordpress的qq邮件列表qq邮件列表订阅rss源地址怎么找
  • 用腾讯云做购物网站视频做网站保证效果
  • 山东省建设工程管理局网站ps制作网站logo
  • 响应式网站宽度236企业邮箱登陆入口