浏览器多线程到事件循环机制
浏览器与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…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
