浏览器的事件循环机制

一、请简述浏览器的事件循环机制(Event Loop)基本原理

浏览器的事件循环机制是用于协调处理 JavaScript 中的异步任务与同步任务执行顺序的一种机制,它确保了代码能够按照合理的顺序执行,避免阻塞页面渲染等情况。其基本原理如下:

  • 任务分类
    • 同步任务:指那些会立即执行的任务,按照代码编写的顺序依次执行,比如简单的变量声明、函数调用(非异步相关的)等,它们会在主线程上按顺序被执行完。例如这里的变量声明和函数调用及最后的 console.log 操作都是同步任务,会依次执行。
    • 异步任务:不会立即执行,而是会在合适的时机被放入任务队列(也叫消息队列)中等待执行,常见的异步任务有定时器任务(setTimeoutsetInterval)、DOM 事件回调、网络请求回调(如 fetch 回调等)。例如:

      这个 setTimeout 里的回调函数就是异步任务,会等待 1000 毫秒后被放入任务队列。

    • 执行流程
      • 首先,JavaScript 主线程会先执行所有的同步任务,在执行同步任务过程中如果遇到异步任务,会将异步任务交给对应的浏览器模块(比如定时器交给浏览器的定时器模块管理,网络请求交给网络模块等),主线程继续执行后续的同步任务,直至所有同步任务执行完毕。
      • 主线程任务执行完后,会去检查任务队列(消息队列),如果任务队列中有任务,就会按照先进先出的顺序将任务取出,放到主线程中执行,每执行完一个任务,就会再次查看任务队列是否还有任务,如此循环往复,这个不断检查并执行任务队列中任务的过程就是事件循环。

二、宏任务(Macro Task)和微任务(Micro Task)分别有哪些,它们在事件循环中的执行顺序是怎样的?

  • 宏任务示例及来源
    • 常见的宏任务类型:包括 setTimeoutsetIntervalI/O 操作(比如读取文件等,不过在浏览器端主要涉及网络请求等类似的异步 I/O)、script(整体的 JavaScript 脚本代码初始执行也可看作一个宏任务)、UI render(浏览器的页面渲染工作通常也会在特定的宏任务执行间隙进行)等。例如:
    • 宏任务执行特点:宏任务会按照它们被添加到任务队列的顺序依次执行,每次执行完一个宏任务后,如果当前宏任务执行过程中产生了微任务,会先处理完微任务,再去执行下一个宏任务。

    • 微任务示例及来源

      • 常见的微任务类型:主要有 Promise.then()MutationObserver(用于监听 DOM 变化的回调)、process.nextTick(在 Node.js 环境中,不过面试中常和浏览器事件循环对比提及)等。例如:这里 Promise.resolve().then() 里的回调就是微任务。
      • 微任务执行特点:微任务会在当前宏任务执行结束后、下一个宏任务开始执行前被执行,并且微任务队列中的所有微任务会一次性执行完,如果在执行微任务过程中又产生了新的微任务,会继续执行新产生的微任务,直到微任务队列清空,才会进入下一个宏任务的执行阶段。
      •  

        所以整体的执行顺序大致是:同步任务 -> 微任务队列(清空) -> 宏任务 1 -> 微任务队列(清空) -> 宏任务 2 -> 微任务队列(清空)…… 以此类推。

三、为什么 setTimeout 回调函数的执行时间可能会不准确,结合事件循环机制解释一下

虽然 setTimeout 可以设置一个延迟时间,比如 setTimeout(() => { console.log('test'); }, 1000); 看似是 1000 毫秒后执行回调函数,但实际执行时间可能不准确,原因如下:

  • 任务队列排队问题
    setTimeout 只是将回调任务添加到了任务队列中,当设定的延迟时间到了之后,它的回调任务才会被放入任务队列,但它具体何时能执行取决于任务队列前面还有多少任务在排队等待执行。例如,如果前面已经有大量的宏任务或者微任务在排队,即使到了设定的延迟时间,它也得等前面的任务都执行完才能轮到它执行,所以实际执行时间就会晚于设定的延迟时间。

  • 浏览器资源分配情况
    浏览器的资源是有限的,主线程需要兼顾很多方面,比如页面渲染、处理用户交互等同时还得执行任务队列中的任务。有时候如果浏览器正在忙于处理页面渲染或者其他高优先级的任务,那么对于任务队列中 setTimeout 回调这样的任务处理就会有延迟,导致其执行时间不准。

  • 最小延迟限制
    大部分浏览器为了性能等因素考虑,对 setTimeout 有一个最小延迟限制,通常是 4 毫秒左右(不同浏览器可能略有差异)。也就是说,即使你设置的延迟时间是 0 毫秒,实际上它最少也得等待大概 4 毫秒后才可能被放入任务队列(只是可能,还得看前面排队情况),这也会使得执行时间和预期设置的不一致。

四、如何理解 async/await 与事件循环机制的关系?

async/await 是基于 JavaScript 中的 Promise 和生成器(generator)等底层机制实现的一种用于处理异步代码的语法糖,它和事件循环机制密切相关:

  • async 函数本身的执行性质
    async 函数在执行时,它内部的代码一开始是同步执行的,直到遇到第一个 await 关键字。例如

    这里 console.log('开始执行 async 函数') 会先同步执行,当遇到 await 时,async 函数会暂停执行,并将 await 后面跟着的 Promise 的 then 方法(也就是 await 等待 Promise 状态变为 fulfilled 后要执行的后续逻辑)作为一个微任务添加到微任务队列中,然后主线程继续执行其他同步任务(比如上面示例中的 console.log('外部同步任务'))。

  • await 与微任务的关联
    当 await 所等待的 Promise 状态变为 fulfilled 时,其对应的 then 回调(也就是 await 后续的代码逻辑)作为微任务会在当前宏任务执行结束后被执行,这符合微任务在事件循环中的执行顺序规则。例如,继续完善上面的示例:执行顺序会是:先执行 console.log('开始执行 async 函数'),然后遇到 await,暂停 async 函数执行,添加 await 后续逻辑为微任务,接着执行 console.log('外部同步任务'),再执行 Promise.resolve().then() 这个额外的微任务,最后执行 await 之后 async 函数里的 console.log('await 之后继续执行,结果为:', result) 等后续逻辑,这个过程充分体现了 async/await 遵循事件循环机制中微任务的执行顺序特点,让异步代码可以更清晰地按照顺序执行,类似同步代码的书写体验。

五、结合事件循环机制,说说页面渲染和 JavaScript 执行是如何协调的?

在浏览器中,页面渲染和 JavaScript 执行的协调是通过事件循环机制来实现的:

  • 初始页面渲染与 JavaScript 执行顺序
    当浏览器加载一个网页时,首先会解析 HTML 文档构建 DOM 树,在这个过程中如果遇到 script 标签内的 JavaScript 代码(内联代码或者外部引入的脚本文件),会暂停 DOM 树的构建,先去执行 JavaScript 代码(此时 JavaScript 代码作为一个宏任务开始执行),等 JavaScript 代码执行完后,再继续构建 DOM 树。例如,以下简单的 HTML 页面结构示例:浏览器先解析到 script 标签时,会先执行里面的 console.log('页面中的JavaScript代码执行') 这个同步任务,然后再继续解析后面的 HTML 元素构建 DOM 树,创建 #app 这个 div 元素对应的 DOM 节点等后续操作。
  • 后续页面渲染时机
    在 JavaScript 执行的过程中(每个宏任务执行阶段),如果修改了 DOM 元素相关属性或者结构等,浏览器并不会立即进行页面渲染,而是等到当前宏任务执行完毕,并且微任务队列也清空后,才会根据修改后的 DOM 情况进行页面渲染(将新的 DOM 结构、样式等呈现到页面上),这个页面渲染操作本身也是一个宏任务的一部分(可以理解为浏览器内部的一个特定宏任务环节)。例如:

    所以,通过事件循环机制,页面渲染和 JavaScript 执行有序地交替进行,既保证了 JavaScript 代码能够按规则操作 DOM 等资源,又能适时地将页面更新呈现给用户,避免渲染的混乱和无序。

    总之,掌握浏览器的事件循环机制对于理解前端代码的执行顺序、异步处理以及页面渲染等诸多方面都非常关键,在前端面试中也是经常考查的重点内容。

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

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

相关文章

GaussDB 华为高斯数据库

GaussDB 是华为推出的一款企业级分布式数据库,旨在为企业提供高效、可靠、安全的数据库服务。GaussDB 基于华为在数据库领域的多年积累,结合人工智能技术和分布式架构,支持多种场景的数据存储与管理需求,是云计算、大数据、人工智…

【Word】一键批量引用论文上标——将正文字体改为上标格式

【Word】一键批量引用论文上标——将正文字体改为上标格式 写在最前面Word一键批量引用论文上标技巧分享核心思路:Word 替换功能 通配符步骤详解1. 打开 Word 替换功能2. 输入通配符模式3. 设置替换格式为上标4. 批量替换 实际效果展示技巧扩展 🌈你好呀…

SAP 零售方案 CAR 系统的介绍与研究

前言 当今时代,零售业务是充满活力和活力的业务领域之一。每天,由于销售运营和客户行为,它都会生成大量数据。因此,公司迫切需要管理数据并从中检索见解。它将帮助公司朝着正确的方向发展他们的业务。 这就是为什么公司用来处理…

【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境

兵马未动,粮草先行。作为深度学习的初学者,快速搭建一个属于自己的开发环境就是头等大事,可以让我们节省许多的时间。这一期我们主要讲一讲2024年最新pytorchcudacudnn下载安装搭建开发环境,以及安装过程中可能遇到的一些问题以及…

STM32-- 串口介绍

rs485、rs232、rs422 rs485使用: max3485:3.3v左右驱动 max485:5v左右驱动,不过有时候3.3v驱动也可以使用,具体有什么问题或者通过电路规避问题还没有了解过。 rs485和rs422有相同的地方,485满足422的规…

python oa服务器巡检报告脚本的重构和修改(适应数盾OTP)有空再去改

Two-Step Vertification required: Please enter the mobile app OTPverification code: 01.因为巡检的服务器要双因子认证登录,也就是登录堡垒机时还要输入验证码。这对我的巡检查服务器的工作带来了不便。它的机制是每一次登录,算一次会话…

AI安全:从现实关切到未来展望

近年来,人工智能技术飞速发展,从简单的图像识别到生成对话,从自动驾驶到医疗诊断,AI技术正深刻改变着我们的生活。然而,伴随着这些进步,AI的安全性和可控性问题也日益凸显。这不仅涉及技术层面的挑战&#…

c++ 笔记

基础知识 1. 指针、引用2. 数组3. 缺省参数4. 函数重载5. 内联函数6. 宏7. auto8. const9. 类和对象10. 类的6个默认成员函数11. 初始化列表12. this指针13. C/C的区别14. C 三大特性15. 结构体内存对齐规则16. explicit17. static18. 友元类、友元函数19. 内部类20. 内存管理&…

介绍一下strncmp(c基础)

strncmp是strcmp的进阶版 链接介绍一下strcmp(c基础)-CSDN博客 作用 比较两个字符串的前n位 格式 #include <string.h> strncmp (arr1,arr2,n); 工作原理&#xff1a;strcmp函数按照ACII&#xff08;字符编码顺序&#xff09;比较两个字符串。它从两个字符串的第一…

得物彩虹桥架构演进之路-负载均衡篇

文 / 新一 一、前言 一年一更的彩虹桥系列又来了&#xff0c;在前面两期我们分享了在稳定性和性能2个层面的一些演进&优化思路。近期我们针对彩虹桥 Proxy 负载均衡层面的架构做了一次升级&#xff0c;目前新架构已经部署完成&#xff0c;生产环境正在逐步升级中&#xf…

【ubuntu】数学人的环境搭建

Python 语言环境 python 的 pip 第三方库管理 sudo apt install python3-pippython 的 idle 界面 sudo apt install idle3R 语言环境 sudo apt install r-cran-zoo### RStudio 界面 ubuntu sudo snap install rstudio --classicJulia 语言环境 sudo snap install julia --…

02:spring之AOP

一&#xff1a;AOP 简介 1&#xff1a;AOP的概念 AOP&#xff0c;Aspect Oriented Programming&#xff0c;面向切面编程&#xff0c;是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象&#xff0c;一个对象包括静态的属性信息&#xff0c;包括动态的方法信息等。而AOP是…

springboot整合hive

springboot整合hive pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…

初级数据结构——树

目录 前言一、树的基本概念二、二叉树三、树的表示方法四、树的遍历树的代码模版五、经典例题[2236. 判断根结点是否等于子结点之和](https://leetcode.cn/problems/root-equals-sum-of-children/description/)代码题解 六、总结结语 前言 从这一期开始数据结构开始有那么一点…

FreeRTOS信号量(二)

目录 1、计数型信号量简介 1、事件计数 2、资源管理 2、创建计数型信号量 ​编辑1、函数xSemaphoreCreateCounting() 2、函数xSemaphoreCreateCountingStatic() 3 、计数型信号量创建过程分析 4、释放和获取计数信号量 信号量的释放 1 、函数 xSemaphoreGive() 2、函…

加载指定会话最近消息

加载指定会话最近消息 前言 上一集我们就把三个标签页的加载列表的任务给完成啦&#xff01;那么我们这一集就来完成加载指定绘画最近消息的任务。 需求分析 我们点击了某个会话之后&#xff0c;我们就会去显示我们的会话的最近的N条消息。请看下图。 我们这里涉及到两个区…

SpringBoot3+SpringDataJPA+Ehcache3做分页查询的缓存优化

前言&#xff1a;关于集成Ehcache3的集成&#xff0c;需要了解的可以出门左转&#xff1a; https://blog.csdn.net/qq_42755868/article/details/143870473 这里 本文也是基于这个前置条件写的。大佬可以忽略哈。 基于上文&#xff1a;我们在做分页查询的时候&#xff0c;可以…

VS2022进行Libigl库编译

目录 一 编译OK 二 编译难点 2.1 cmake问题 2.2 文件编码问题 三 调用链接 一 编译OK 二 编译难点 2.1 cmake问题 vs2022直接多次cmake生成即可。 2.2 文件编码问题 格式保存为GB2312. 三 调用链接 https://github.com/libigl/libigl-example-project

风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计

风尚云网前端学习&#xff1a;一个简易前端新手友好的HTML5页面布局与样式设计 简介 在前端开发的世界里&#xff0c;HTML5和CSS3是构建现代网页的基石。本文将通过一个简单的HTML5页面模板&#xff0c;展示如何使用HTML5的结构化元素和CSS3的样式特性&#xff0c;来创建一个…

返回流类型接口的错误信息处理

返回流类型接口的错误信息处理 前言axios拦截器src/utils/request.ts对应接口 前言 返回流类型接口需要在响应成功回调里拦截&#xff0c;且该接口的status始终是200&#xff0c;尽管后端返回的code可能是非2xx&#xff0c;因此返回流类型的接口&#xff0c;其错误信息需要单独…