浏览器多线程到事件循环机制
浏览器与js运行机制
进程与线程
进程
进程是CPU分配资源的最小单位,它是一个可以自己独立运行且拥有自己资源空间的任务程序;包括程序以及程序所使用的内存及系统资源
线程
线程是CPU调度的最小单位,它就是程序中的一个执行流;也可以理解为一个进程代码的不同执行路径
一个进程中只有一个执行流就是单线程,程序按照顺序执行,前面的处理好才执行后面的
一个进程中有多个执行流就是多线程,多个线程并行执行各自的任务
JS为什么是单线程
多线程的复杂性,多线程操作需要加锁,编码的复杂性会增高。而且,如果同时操作 DOM ,在多线程不加锁的情况下,最终会导致 DOM 渲染的结果不可预期
HTML5提出了 Web Worker标准,允许JS脚本创建多个线程,但是子线程完全收主线程控制,而且不得操作DOM,所以它并没改变JS单线程的本质
浏览器多线程
浏览器是多进程
我们没打开一个Tab标签页就会产生一个进程
如果我们打开多个Tab标签页,其中一个Tab标签页崩溃了,影响整个浏览器,那体验肯定是不行的,所以不可能是单进程;每个进程有多个线程都会占用资源,所以我们打开多个标签页可能会卡,谷歌就有标签页限制
浏览器有那些进程
Broswer进程
浏览器的主进程,该进程只有一个,主要是一个协调、主控的作用
负责浏览器的页面展示、交互;(前进后退)
负责页面的管理,创建和销毁其他进程
网络资源的管理,下载等
第三方插件进程
使用插件是才创建,一个插件对应一个进程
GPU进程
该进程只有一个,负责3D的绘制等
Render渲染进程
渲染进程就是我们所说的浏览器内核,内部是多线程
每个tab页面都有一个渲染进程
主要作用是页面渲染、脚本执行,事件处理等
Render进程及它主要的线程
render进程是多线程
GUI渲染线程
主要负责页面的渲染,解析html、css,生成DOM树、CSS规则树,构建Render树,页面的布局绘制
JS引擎线程
JS引擎线程(比如V8引擎)是JS内核;负责解析JavaScript脚本,运行代码
一个render进程中,无论什么时候都只有一个JS线程再运行JS程序
JS引擎线程与GUI渲染线程互斥:
因为JS引擎可以修改DOM树,那么如果JS引擎在执行修改了DOM结构的同时,GUI线程也在渲染页面,那么这样就会导致渲染线程获取的DOM的元素信息可能与JS引擎操作DOM后的结果不一致。
当JS引擎执行的时候,GUI线程需要被冻结,但是GUI的渲染会被保存在一个队列当中,等待JS引擎空闲的时候执行渲染
如果JS引擎正在进行CPU密集型计算,那么JS引擎将会阻塞,长时间不空闲,导致渲染进程一直不能执行渲染,页面就会看起来卡顿卡顿的,渲染不连贯。所以,要尽量避免JS执行时间过长。
事件触发线程
属于浏览器而不是JS引擎
用来控制事件循环,管理事件队列
当js执行碰到事件绑定和异步操作会走事件触发线程,将对应的事件添加到对用的线程中;当事件触发或异步有了结果将它们的回调事件添加到事件队列等待JS引擎事件线程处理
因为JS是单线程,所以事件队列中的事件都要等待JS引擎线程处理
定时触发线程
浏览器定计数器不是在 JS 引擎线程中计数的(JS引擎是单线程,如果处于阻塞线程状态就计不了时,JS引擎线程与GUI渲染线程互斥,GUI进程执行的时候就阻塞了JS引擎线程,就记不了时了)
计时完成后,会添加到事件触发线程的事件队列中
W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms
异步http请求线程
当执行到一个http异步请求时,就把异步请求事件添加到异步请求线程,等收到响应(准确来说应该是http状态变化),再把回调函数添加到事件队列,等待js引擎线程来执行
事件循环机制Event Loop
JS分为同步任务和异步任务,同步任务在主线程也就是JS引擎线程上执行
除了主线程之外,我们的事件触发线程中有一个任务队列,只要异步事件有了结果就会在任务队列总添加它的回调事件;任务队列中由两个队列,一个宏任务队列,一个时微任务队列
1》首先我们的同步任务会进入主执行栈,异步任务交给事件触发线程,异步任务有了结果才会被添加到事件队列中
2》当我们主执行栈中的代码执行之后,会先去微任务队列读取任务,然后执行
3》执行完所有的微任务后又会到微任务队列中读取微任务(因为刚才可能产生了新的微任务),直到没有读取到微任务,然后GUI渲染线程会进行一次渲染(会阻塞js执行)
4》渲染后会去宏任务队列读取宏任务,然后执行
5》宏任务执行完毕会去微任务队列读取任务,有就执行,然后和之前一样,读取微任务直到没有微任务进行渲染,一个事件循环结束
6》渲染页面,再读取、执行宏任务之前,执行完所有微任务之后渲染一次页面
6》重复上面的事情,微任务-渲染-宏任务

宏任务
所有微任务执行完后,下一个宏任务执行前,GUI渲染线程会渲染一次页面
常见宏任务:
setTimeout
setInterval
requestAnimationFrame(浏览器)
微任务
常见微任务
Promise.then()
Promise.catch()
Promise.finally()
process.nextTick (node)
Object.observe
this.$nextTick()
Vue异步执行DOM更新。只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作上非常重要。然后,在下一个的事件循环“tick”中,Vue刷新队列并执行实际 (已去重的) 工作。
nextTick会创建一个微任务(或宏任务),将其内部回调推入微任务队列中,vue中一个事件循环中所有dom更新也是一个微任务,dom更新在这个微任务之前进入微任务队列中,是先更新dom再执行this.$next中的代码,所以可以再里面获取到更新后的dom
nextTick异步处理更新队列的逻辑:在下一个的事件循环“tick”中,去刷新队列,依次尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境都不支持,则会采用 setTimeout(fn, 0) 代替;所以this.$nextTick(vue中) 可能是一个微任务也可能时宏任务
我们再来梳理一遍上面从数据变更到 dom 更新之前的整个流程
- 修改响应式数据
- 触发
Object.defineProperty中的set - 发布通知
- 触发
Watcher中的update方法, update方法中把Watcher缓冲到一个队列- 刷新队列的方法(其实就是更新 dom 的方法)传到
nextTick方法中 nextTick方法中把传进来的callback都放在一个数组callbacks中,然后放在异步队列中去执行
然后这时你调用了 $nextTick 方法,传进来一个获取最新 dom 的回调,这个回调也会推到那个数组 callbacks 中,此时遍历 callbacks 并执行所有回调的动作已经放到了异步队列中,到这(假设你后面没有其他的代码了)所有的同步代码就执行完了,然后开始执行异步队列中的任务,更新 dom 的方法是最先被推进去的,所以就先执行,你传进来的获取最新 dom 的回调是最后传进来的所以最后执行,显而易见,当执行到你的回调的时候,前面更新 dom 的动作都已经完成了,所以现在你的回调就能获取到最新的 dom 了。
相关文章:
浏览器多线程到事件循环机制
浏览器与js运行机制 进程与线程 进程 进程是CPU分配资源的最小单位,它是一个可以自己独立运行且拥有自己资源空间的任务程序;包括程序以及程序所使用的内存及系统资源 线程 线程是CPU调度的最小单位,它就是程序中的一个执行流࿱…...
Lambda表达式的本质
一直想写一篇文章,来总结lambda表达式,但是之前感觉总结的不是特别到位,现在看了几篇文章和视频后,感觉对lambda表达式有了比较深刻的认识,现在进行记录总结如下: lambda表达式又叫做匿名函数,…...
类的加载过程(生命周期)
类的加载过程(生命周期) 一、装载:通过一个类的全限定名获取定义此类的二进制字节流将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构在内存中生成一个代表这个类的java.lang.Class对象(将字节码加载到内存中),作为…...
2023最新谷粒商城笔记之MQ消息队列篇(全文总共13万字,超详细)
MQ消息队列 其实队列JDK中本身就有,不过这种队列也只能单体服务可能会使用,一旦项目使用的分布式架构,那么一定还是需要用到一个消息中间件的。我们引入消息队列的原因就是对我们的页面相应速度再优化,让用户的体验更好ÿ…...
多变量线性回归模型
多变量线性回归模型 模型参数为n1维向量,此时模型公式为 hθ(x)θ0x0θ1x1θ2x2...θnxnh_{\theta}(x)\theta_{0}x_{0}\theta_{1}x_{1}\theta_{2}x_{2}...\theta_{n}x_{n} hθ(x)θ0x0θ1x1θ2x2...θnxn 可以简化为 hθ(x)θTXh_{\theta}(x)\th…...
php 基于ICMP协议实现一个ping命令
php 基于ICMP协议实现一个ping命令 网络协议是什么ICMP 协议什么是ICMP?ICMP 的主要功能ICMP 在 IPv4 和 IPv6 的封装Wireshark抓包ICMP 请求包分析PHP构建 ICMP 数据包php中的 pack & unpack 函数字节和字符packunpackICMP计算校验和步骤总结网络协议是什么 网络协议&…...
Java基本数据类型
1.概述 佛说,大千世界,无奇不有。在这个世界里,物种的多样性,遍地开花,同样,在Java的世界里,也有着异曲同工之妙,Java秉承面向对象的特性,必然少不了区分对象的类型&…...
English Learning - L2 语音作业打卡 Day2 2023.2.22 周三
English Learning - L2 语音作业打卡 Day2 2023.2.22 周三💌 发音小贴士:💌 当日目标音发音规则/技巧:🍭 Part 1【热身练习】🍭 Part2【练习内容】🍭【练习感受】🍓元音[ ɑː ]&…...
45. 跳跃游戏 II
题目: 45. 跳跃游戏 II难度中等1974收藏分享切换为英文接收动态反馈给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 num…...
应届生Java面试50题线程篇(含解析)
什么是线程? 答:线程是操作系统能够进行运算调度的最小单位,是程序执行流的最小单元。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。 创建线程的方式有哪些?各自的优缺点是什么? 继承 Thread 类&…...
【数据库】第七章 数据库设计
第七章数据库设计 数据库设计概述 数据库设计的基本步骤 需求分析概念结构设计逻辑结构设计物理结构设计数据库实施数据库运行和维护 需求分析 收集需求,理解需求 收集各个角色的需求 概念数据库设计 建立概念模型 ,E-R图/IDEF1x图 消除冲突&…...
Burp Suite 常用模块简介
Burp Suite 常用模块分为 目标站点(target)模块 代理(proxy)模块 攻击(Intruder)模块 重放(Repeater) 模块 Target模块是对站点资源的收集,与站点各资源包发出和相应包的记录 Proxy模块是核心模块,可以拦截数据包发送往浏览器,进行修改后再…...
QML Item和Rectangle详解
1.Item和Rectangle Item类型是Qt Quick中所有可视项的基本类型。 Qt Quick中的所有可视项都继承Item。尽管Item对象没有视觉外观,但它定义了视觉项中常见的所有属性,例如x和y位置、宽度和高度、锚定和键处理支持。 Rectangle继承自Item,多…...
常见前端基础面试题(HTML,CSS,JS)(六)
GET 和 POST 的区别 从 http 协议的角度来说,GET 和 POST 它们都只是请求行中的第一个单词,除了语义不同,其实没有本质的区别。 之所以在实际开发中会产生各种区别,主要是因为浏览器的默认行为造成的。 受浏览器的影响…...
深度学习 李沐报错
3.6. softmax回归的从零开始实现 — 动手学深度学习 2.0.0 documentation softmax从0开始实现 函数执行需要加main指定 改成这样 if __name__"__main__":print(evaluate_accuracy(net, test_iter)) 不然会这样出错 RuntimeError: An attempt has been m…...
【JAVA程序设计】(C00104)基于Springboot的家庭理财管理系统——有文档
基于Springboot的家庭理财管理系统项目简介项目获取开发环境项目技术运行截图运行视频项目简介 基于Springboot开发的家庭理财管理系统设计与实现共分为三个角色:系统管理员、家庭管理员、家庭用户 管理员角色包含以下功能: 用户管理、修改密码、角色管…...
【第五章 AOP概述,底层原理,AOP术语,切入点表达式,AOP操作(基于注解方式,基于xml配置文件)】
第五章 AOP概述,底层原理,AOP术语,切入点表达式,AOP操作(基于注解方式,基于xml配置文件) 1.AOP概述: (1)什么是AOP: ①面向切面编程(…...
面试官: 你知道 JWT、JWE、JWS 、JWK嘛?
想起了 之前做过的 很多 登录授权 的项目 它相比原先的session、cookie来说,更快更安全,跨域也不再是问题,更关键的是更加优雅 ,所以今天总结了一篇文章来介绍他 JWT 指JSON Web Token,如果在项目中通过 jjwt 来支持 J…...
基于企业微信应用消息的每日早安推送
基于企业微信应用消息的每日早安推送 第一步:注册企业微信 企业微信注册地址:https://work.weixin.qq.com/wework_admin/register_wx 按照正常流程填写信息即可,个人也可以注册企业微信,不需要公司 注册完成后,登录…...
【数字IC基础】黑盒验证、白盒验证、 灰盒验证
文章目录 一、黑盒验证二、白盒验证三、灰盒验证一、黑盒验证 1、黑盒验证:大多数基于仿真的验证环境都是黑盒验证;2、不需要知道设计的内部结构和特性,只需要在输入端口打激励,观察输出即可;3、验证工程师学习设计的规格,然后编写验证环境中的 drivers, monitors, check…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
