js中的事件循环

浏览器进程模型

在理解什么叫事件循环前,我们需要先知道浏览器的进程模型
现代浏览器的功能极度复杂,为了能确保各个部分独立运行互不影响,浏览器会在启动之时开启多个进程,具体而言可以分为以下三种

  1. 浏览器进程
    负责浏览器的用户交互,子进程管理,浏览器页面显示等等,浏览器进程是最先被启动的进程,将由它来启动并维护其他进程
  2. 网络进程
    负责浏览器的网络通信,加载网络资源,会在内部开启多个线程来维护不同的网络任务
  3. 渲染进程
    渲染进程不同于其他进程,它一次只能开启一个线程,这个线程也被称为渲染主线程,将由它负责渲染页面,执行js等等

进程模型

默认情况下,现代浏览器都是开启一个页面则开启一个渲染进程,具体可以通过浏览器的任务管理器来查看

管理器

渲染主线程

渲染主线程可以说是浏览器中最繁忙的线程,因为各种各样的原因导致渲染进程一次只能开启一个渲染主进程,所以主线程将负责包括但不限于以下内容

  1. 解析HTML
  2. 解析CSS
  3. 执行JS代码
  4. 处理图层

可以看到渲染主线程的任务多且杂,但渲染主线程只有一个,一次只能执行一个任务,那任务与任务之间又如何调度

渲染主线程的解决方案是将任务排队

消息队列

渲染主线程会维护消息队列,所有任务都需要按照先来后到的顺序放入消息队列中,渲染主线程则会依次取出 消息队列中的任务执行,具体有以下步骤

  1. 最开始渲染主线程会开启一个死循环
  2. 每一次循环渲染主线程都会检测消息队列中是否有任务,如果有就取出执行,没有就进入休眠状态
  3. 其他线程可以随时向消息队列中添加任务,如果此时渲染主线程处于休眠状态则会被唤醒

基于这样一个循环,我们的渲染主线程就能有条不紊的执行下去了

在这里插入图片描述

异步

到现在为止一切似乎都没什么问题,任务在消息队列的调度下能有序执行,最大的困难便解决了,但任务不全都是同步执行,有些任务浏览器遇到了之后并不立刻执行,如setTimeOutsetIntervalPromise等等,如果直接将其当做同步任务执行的话就会导致页面阻塞

阻塞
为了保证用户的使用体验,使页面不被卡死,因此浏览器采用异步的方式来解决这个问题,具体步骤如下

  1. 当渲染主线程遇到异步任务时会通知对应的线程,当前任务结束,从消息队列取出任务继续执行
  2. 其他线程开始监控,待任务到达触发时机就会将任务的回调函数包装成任务放入消息队列中
  3. 渲染主线程会自始至终从消息队列中取出任务执行

异步任务处理
当然,所有异步任务不可能都由一个线程处理,不同的异步任务会有对应的线程接管

浏览器通过使用异步的形式来使渲染主线程不会出现阻塞

由此我们能得到两个结论

单线程是异步产生的原因
事件循环是异步的实现方式

任务优先级

到了这里,似乎事件循环我们已经了解的差不多了,但还有一些疑问我们仍未解决,任务与任务之间有优先级的区别吗
事实上,任务与任务之间并没有优先级的区别,都是先进先出,但消息队列与消息队列间有着不同的优先级
消息队列向来都不只有一个,具体可以分为宏队列微队列
然而随着现代浏览器复杂度的急剧提升,原有的划分方式已不满足于现在需要,所以目前的消息队列划分如下

  1. 每个任务都会有一个任务类型同一个类型的任务必须在同一个队列不同类型的任务可以在同一个队列
  2. 每个浏览器都必须拥有一个微队列微队列里的任务优先于其他队列里的任务执行
  3. 其他队列里的任务浏览器可以按照实际情况执行

在这里插入图片描述

事件循环

最后,我们再来总结一下什么是事件循环

事件循环是浏览器渲染主线程的主要工作方式,因为各种各样的原因,浏览器开辟的渲染进程只会存在一个渲染主线程,这也就决定js是一门单线程的语言,同时渲染主线程负责的任务十分繁杂,包括渲染HTML,CSS,执行JS,每秒重绘多少多少次,布局等等,为了保证所有任务都能稳定有序执行,浏览器会维护消息队列来存放任务,其他线程可以向消息队列中提交任务,渲染主线程每次都会从消息队列中取出第一个任务来执行,如果没有任务渲染主线程就会进入休眠,待消息队列中有了新的任务就会被唤醒,如果是异步任务则会交由其他线程托管,待任务需要执行时将事件的回调函数包装成任务放入消息队列中。根据W3C规定,每个任务都有一个消息类型,同一类型的任务必须要在同一个消息队列中,不同类型的任务可以在一个消息队列中,每个浏览器必须要有一个微队列,并且微队列中的任务要先于其他消息队列中的任务执行。

关于JS中能否做到精准计时

严格上来说是不能的,主要原因有以下几点

  1. 计算机内没有原子钟,无法做到精确计时
  2. js的计时也是调用系统级的函数,会有些许偏差
  3. W3C规定计时器嵌套超过4层的话从第5层开始强制计时器有5ms延时
  4. 当计时器结束,任务进入消息队列也不是立刻执行的,需要等待渲染主线程的调用,这也会有时间上的偏差

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Pulsar服务端处理消费者请求以及源码解析

引言 处理读写是Pulsar服务端最基本也是最重要的逻辑,今天就重点看看服务端是如何处理的读请求也就是消费者请求 正文 Pulsar服务端处理消费者请求的流程大致如下图所示 消费者通过TCP向服务端发起消息拉取请求Broker会根据请求中携带的ID来获取在服务端对应的…

Lua 和 Love 2d 教程 二十一点朴克牌 (上篇lua源码)

GitCode - 开发者的代码家园 Lua版完整原码 规则 庄家和玩家各发两张牌。庄家的第一张牌对玩家是隐藏的。 玩家可以拿牌(即拿另一张牌)或 停牌(即停止拿牌)。 如果玩家手牌的总价值超过 21,那么他们就爆掉了。 面牌…

WIFI|软体 茶凳浅谈 高通WIN QSDK - IPQ6000 与 88Q2112 的相遇

Qualcomm IPQ 系列的Ethernet IC 搭配的有 QCA8075, QCA8081 … 等等Qualcomm自家出产的芯片。QSDK中内建可以支持的3rd party芯片,却寥寥可数。日前,客户使用车载以太网 - 88Q2112 - Marvell与IPQ6000做搭配。将之记录下来,以供参考。 方…

传输层 --- TCP (下篇)

目录 1. 超时重传 1.1. 数据段丢包 1.2. 接收方发送的ACK丢包 1.3. 超时重传的超时时间如何设置 2. 流量控制 3. 滑动窗口 3.1. 初步理解滑动窗口 3.2. 滑动窗口的完善理解 3.3. 关于快重传的补充 3.4. 快重传和超时重传的区别 4. 拥塞控制 4.1. 拥塞控制的宏观认识…

2024年华为OD机试真题-推荐多样性-Java-OD统一考试(C卷)

题目描述: 推荐多样性需要从多个列表中选择元素,一次性要返回N屏数据(窗口数量),每屏展示K个元素(窗口大小),选择策略: 1. 各个列表元素需要做穿插处理,即先从…

新版HI3559AV100开发注意事项(三)

新版HI3559AV100开发注意事项(三) 十九、用的sdk是Hi3559V200_MobileCam_SDK_V1.0.1.5 播放AAC音频文件,adec->ao;adec的初始化里面包括了aaclc解码器的注册,可是在HI_MPI_ADEC_RegisterDecoder(&s32Handle, &stAac);…

一篇文章带你学会7大基本算法(2024最新保姆级教程)

🏠个人主页:尘觉主页 文章目录 算法 - 排序约定选择排序冒泡排序插入排序希尔排序归并排序1. 归并方法2. 自顶向下归并排序3. 自底向上归并排序 快速排序1. 基本算法2. 切分3. 性能分析4. 算法改进4.1 切换到插入排序4.2 三数取中4.3 三向切分 5. 基于切…

vue 打包 插槽 inject reactive draggable 动画 foreach pinia状态管理

在Vue项目中,当涉及到打包、插槽(Slots)、inject/reactive、draggable、transition、foreach以及pinia时,这些都是Vue框架的不同特性和库,它们各自在Vue应用中有不同的用途。下面我将逐一解释这些概念,并说…

用 Wireshark 解码 H.264

H264,你不知道的小技巧-腾讯云开发者社区-腾讯云 这篇文章写的非常好 这里仅做几点补充 init.lua内容: -- Set enable_lua to false to disable Lua support. enable_lua trueif not enable_lua thenreturn end-- If false and Wireshark was start…

Vue使用高德地图(快速上手)

1.在高德平台注册账号 2.我的 > 管理管理中添加Key 3.安装依赖 npm i amap/amap-jsapi-loader --save 或 yarn add amap/amap-jsapi-loader --save 4.导入 AMapLoade import AMapLoader from amap/amap-jsapi-loader; 5.直接上代码,做好了注释(初…

单细胞RNA测序(scRNA-seq)SRA数据下载及fastq-dumq数据拆分

单细胞RNA测序(scRNA-seq)入门可查看以下文章: 单细胞RNA测序(scRNA-seq)工作流程入门 单细胞RNA测序(scRNA-seq)细胞分离与扩增 1. NCBI查询scRNA-seq SRA数据 NCBI地址: https…

前视声呐目标识别定位(六)-代码解析之目标截图并传输

前视声呐目标识别定位(一)-基础知识 前视声呐目标识别定位(二)-目标识别定位模块 前视声呐目标识别定位(三)-部署至机器人 前视声呐目标识别定位(四)-代码解析之启动识别模块 …

51单片机实验02- P0口流水灯实验

目录 一、实验的背景和意义 二、实验目的 三、实验步骤 四、实验仪器 五、实验任务及要求 1,从led4开始右移 1)思路 ①起始灯 (led4) ②右移 2)效果 3)代码☀ 2,从其他小灯并向右依…

服务器设置了端口映射之后外网还是访问不了服务器

目录 排查思路参考: 1、确认服务是否在运行 2、确认端口映射设置是否正确 3、使用防火墙测试到服务器的连通性 4、检查服务内部的配置 5、解决办法 6、学习小分享 我们在一个完整的网络数据存储服务系统设备中都会存有业务服务器、防火墙、交换机、路由器&a…

【Laravel】09 用模型批量赋值简化代码 数据库关系

【Laravel】09 用模型批量赋值简化代码 & 数据库关系 1. 用模型批量赋值简化代码2. 数据库关系 1. 用模型批量赋值简化代码 原来存储一个值 2. 数据库关系 这里可以看到两个SQL是一样的

STM32之HAL开发——不同系列SPI功能对比(附STM32Cube配置)

不同系列STM32——SPI框图 F1系列框图 F4系列框图 TI模式时序图特性 F7系列框图 H7系列框图 注意:F7系列以及H7系列支持Quad-SPI模式,可以连接单,双或者四条数据线的Flash存储介质。 SPI——Cube配置流程 RCC时钟源配置 SYS系统调试模式配…

Spring 详细总结

文章目录 第一章 IOC容器第一节 Spring简介1、一家公司2、Spring旗下的众多项目3、Spring Framework①Spring Framework优良特性②Spring Framework五大功能模块 第二节 IOC容器概念1、普通容器①生活中的普通容器②程序中的普通容器 2、复杂容器①生活中的复杂容器②程序中的复…

MySQL、Oracle查看字节和字符长度个数的函数

目录 0. 总结1. MySQL1.1. 造数据1.2. 查看字符/字节个数 2. Oracle2.1. 造数据2.2. 查看字符/字节个数 0. 总结 databasecharbyteMySQLchar_length()length()Oraclelength()lengthB() 1. MySQL 1.1. 造数据 sql drop table if exists demo; create table demo (id …

Cesium 批量种树

1、准备树种建模 分各种级别建模LOD1-LODN 其中meta.json长这样: Gltf再3Dmax中导出Obj,再通过ObjToGltf的工具转换,参考 https://editor.csdn.net/md/?articleId96484597 2、准备shp点数据。(shp中的点位就是种树的位置) 3、准…

【并发编程】线程安全

线程安全 1. 讲一下 synchronized 关键字的底层原理 1.1 基本使用 如下抢票的代码,如果不加锁,就会出现超卖或者一张票卖给多个人 synchronized,同步【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】 其它线程再想获…