浏览器的渲染原理
以下内容来源于渡一前端大师课,仅作个人学习记录。
渲染的第一步是 解析HTML
解析过程中遇到CSS解析CSS,遇到JS执行JS。为了提高解析效率,浏览器在开始解析之前,会启动一个预解析的线程,率先下载HTML中的外部CSS文件和外部的JS文件。
如果主线程解析到link位置,此时外部的CSS文件还没有下载解析好,主线程不会等待,继续解析后续的HTML。这是因为下载和解析CSS的工作是在预解析线程中进行的。这就是CSS不会阻塞HTML解析的根本原因。
如果主线程解析到script位置,会停止解析HTML,转而等待JS文件下载好,并将全局代码解析执行完成后,才能继续解析HTML。这是因为JS代码的执行过程可能会修改当前的DOM树,所以DOM 树的生成必须暂停。这就是JS会阻塞HTML解析的根本原因。
第一步完成后,会得到DOM树和CSSOM树,浏览器的默认样式、内部样式、外部样式、行内样式均会包含在CSSOM树中。
渲染的下一步是 样式计算
主线程会遍历得到的DOM树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style。
在这一过程中,很多预设值会变成绝对值,比如red会变成rgb(255,0,0);相对单位会变成绝对单位,比如em会变成px
这一步完成后,会得到一颗带有样式的DOM树。
接下来是布局,布局完成后会得到布局树。
布局阶段会依次遍历DOM树的每一个节点,计算每个节点的几何信息。例如节点的宽高、相对包含块的位置。
大部分的时候,DOM树和布局树并非一一对应。
比如display:none 的节点没有几何信息,因此不会生成到布局树;又比如使用了伪元素选择器,虽然DOM树中不存在这些伪元素节点,但他们拥有几何信息,所以会生成到布局树中。还有匿名行盒、匿名块盒子等等都会导致DOM树和布局树无法一一对应。
下一步是分层
主线程会使用一套复杂的策略对整个布局树中进行分层。
分层的好处在于,将来某一个层改变后,仅会对该层进行后续处理,从而提升效率。
滚动条、堆叠上下文、transform、opaacity等样式都会或多或少的影响分层结果,也可以通过will-change属性更大程度的影响分层结果。
再下一步是绘制
主线程会为每个层单独产生绘制指令,用于描述这一层的内容该如何画出来。
完成绘制后,主线程将每个图层的绘制信息提交给合成线程,剩余工作将由合成线程完成。
合成线程首先对每个图层进行分块,将其划分为更多的小区域。
他会从线程池中拿取多个线程来完成分块工作
分块完成后,进入光栅化阶段。
合成线程会将块信息交给GPU进程,以极高的速度完成光栅化。
GPU进程会开启多个线程来完成光栅化,并且优先处理靠近视口区域的块。
光栅化的结果,就是一块一块的位图
最后一个阶段就是画了
合成线程拿到每个层,每个块的位图,生产一个个【指引(quad)】信息
指引会表示出每个位图应该画到屏幕的哪个位置,以及会考虑到旋转,缩放等变形。
变形发生在合成线程,与渲染主线程无关,这就是transform效率高的本质原因。
合成线程会把quad提交给GPU进程,由GPU进程产生系统调用,提交给GPU硬件,完成最终的屏幕成像。
来,总结一下:解析HTML,生产dom树和cssom树。
计算样式,让每个dom里边得到最终的样式。
布局,计算出每一个dom节点的几何信息。
然后是分层,这是为了提高后续的渲染效率,他把页面根据一套策略分成几个图层,每个图层可以单独绘制
下一步,产生绘制指令,先画啥再画啥,把这些指令呢,交给合成线程的分块,分块完成之后变成很多个小块,然后对每个小块进行光栅化,优先光栅化靠近屏幕的小块,最后呢,把那些靠近屏幕的小块发送到GPU画出来 ,整个过程就完成了
什么是reflow?
reflow的本质就是重新计算layout树
当进行了会影响布局树的操作后,需要重新计算布局树,会引发layout。
为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当JS代码全部完成后再进行统一计算。所以,改动属性造成的reflow是异步完成的。
也同样因为如此,当JS获取布局属性时,就可能造成无法获取到最新的布局信息。
浏览器再反复权衡下,最终决定获取属性立即reflow。
什么是repaint?
repaint的本质就是重新根据分层信息计算了绘制指令。
当改动了可见样式表后,就需要重新计算,会引发repaint
由于元素的布局信息也属于可见样式,所以reflow一定会引起repaint。
为什么transform的效率高?
因为transform既不会影响布局也不会影响绘制指令,他影响的只是渲染流程的最后一个[draw]阶段,由于draw阶段在合成线程中,所以transform的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌,也不会影响transform的变化。
相关文章:

浏览器的渲染原理
以下内容来源于渡一前端大师课,仅作个人学习记录。 渲染的第一步是 解析HTML 解析过程中遇到CSS解析CSS,遇到JS执行JS。为了提高解析效率,浏览器在开始解析之前,会启动一个预解析的线程,率先下载HTML中的外部CSS文件和…...

从 JSON 转 Java 实体的多种方法详解
将 JSON 数据转换为 Java 对象是现代应用程序开发中常见的任务。在 Java 中,有多种方法可以实现这一目标。本文将详细介绍几种常见的方法,以及它们的优缺点。 1. 手动映射(Manual Mapping) 手动映射是最基础的方法之一ÿ…...

数据库的多表查询(MYSQL)表表联立
根据以上三张表格,对三张表格进行不同的联立,查询并显示符合条件的内容。 1. 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数。 mysql> SELECT d.deptno AS 部门编号, d.dname as 部门名称, d.loc as 部门位置, COUNT(e.emp…...

P8650 [蓝桥杯 2017 省 A] 正则问题(dfs )
多重括号,利用回溯来对上一层括号中的内容进行反馈 实现: 若为 x 长度加一 若为 ( 进入递归计算 (计算相当于子表达式) 若为 ) 结束当前递归 若为 | …...

【ESP32】手势识别实现笔记:红外温度阵列 | 双三次插值 | 神经网络 | TensorFlow | ESP-DL
目录 一、开发环境搭建与新建工程模板1.1、开发环境搭建与卸载1.2、新建工程目录1.3、自定义组件 二、驱动移植与应用开发2.1、I2C驱动移植与AMG8833应用开发2.2、SPI驱动移植与LCD应用开发2.3、绘制温度云图2.4、启用PSRAM(可选)2.5、画面动静和距离检测…...

No matching version found for @babel/compat-data@^7.23.5 处理
npm ERR! notarget No matching version found for babel/compat-data^7.23.5 处理 报错信息 npm WARN ERESOLVE overriding peer dependency npm ERR! code ETARGET npm ERR! notarget No matching version found for babel/compat-data^7.23.5. npm ERR! notarget In most …...

手持机|三防智能手机_4寸/5寸/6寸安卓系统三防手机PDA手持终端方案
随着科技的不断发展,三防手持机作为一种多功能设备,正逐渐在各行业得到广泛应用。这款手持机采用高性能处理器,支持高精度北斗定位和工业本安防爆功能,并具备IP67级防水防尘性能和1.5米防跌落能力。因此,它在仓储管理、…...

蓝桥杯算法心得——仙界诅咒(dfs)
大家好,我是晴天学长,搜索型的dfs,差点开二维矩阵了,仔细一想,没那么夸张啊,哈哈哈,需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪 1…...

List集合,遍历,数据结构
一.List常见的方法: 二. List集合的遍历方式 除了 迭代器遍历 增强for遍历 Lambda表达式遍历,还有自己独有的普通for遍历,列表迭代器遍历 1.迭代器遍历 2.增强for遍历 3.Lambda表达式遍历 4.普通for遍历 5.列表迭代器遍历 列表迭代器相对于…...

2的幂运算
2的幂 描述 : 给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。 如果存在一个整数 x 使得 n 2x ,则认为 n 是 2 的幂次方。 题目 : LeetCode 231.2的幂 : 231. 2 的幂 分…...

优先队列经典例题leetcode思路代码详解
目录 leetcode215题.数组中的第k个最大元素 leetcode347题.前k个高频元素 leetcode295题.数据流的中位数 对优先队列感兴趣的朋友可以去看我上一篇文章。 优先队列基础讲解-CSDN博客 leetcode215题.数组中的第k个最大元素 215. 数组中的第K个最大元素 - 力扣(…...

新型Python环境与依赖管理工具——pipenv
文章目录 pipenv介绍pipenv安装pipenv使用创建虚拟环境删除虚拟环境安装依赖查看包之间的依赖图卸载依赖在虚拟环境中执行命令shell环境下通过requirements.txt安装依赖导出requirements.txt文件查看虚拟环境的路径 pipenv介绍 pipenv可以看做是pip和virtualenv的组合体&#…...

FastDFS+Nginx - 本地搭建文件服务器同时实现在外远程访问「内网穿透」
文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…...

kendo-splitter动态分配分隔框大小
通过size方法,动态改变框大小,参考链接:https://docs.telerik.com/kendo-ui/api/javascript/ui/splitter/methods/size vue画面 <kendo-button type"primary" click"changePane">button</kendo-button><…...

网站提示不安全?
随着互联网的普及和发展,网络安全问题日益严重。黑客攻击、数据泄露、恶意软件等问题层出不穷,给企业和个人带来了巨大的损失。在这个背景下,确保网站安全显得尤为重要,而使用SSL证书是解决这些问题的有效措施。 什么是SSL证书&am…...

C# 泛型编译特性对性能的影响
C#作为一种强类型语言,具有丰富的泛型支持,允许开发者编写可以应对不同数据类型的通用代码。然而,在泛型编译时,针对结构和类作为泛型参数时,会对性能产生不同的影响。 泛型编译行为 在C#中,泛型编译行为取…...

11-30 JavaWeb
修改与删除操作 防止空指针异常 localhost:8080 -> 分页查询 修改流程:(先查后改(两个servlet)) 修改: 传用户id(用户id怎么得到 -> 循环一次得到一个user 对象 user对象里用user.getId()得到用户id) UpdateUserQueryServlet.java (…...

LCR 047. 二叉树剪枝 和 leetCode 1110. 删点成林 + 递归 + 图解
给定一个二叉树 根节点 root ,树的每个节点的值要么是 0,要么是 1。请剪除该二叉树中所有节点的值为 0 的子树。节点 node 的子树为 node 本身,以及所有 node 的后代。 示例 1: 输入: [1,null,0,0,1] 输出: [1,null,0,null,1] 解释: 只有红…...

Flutter笔记:路由观察者
Flutter系列 路由观察者 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/details/134572181 目 录 1. 概述2. 路由…...

【驱动】串口驱动分析(三)-serial driver
简介 前两节我们介绍串口驱动的框架和tty core部分。这节我们介绍和硬件紧密相关的串口驱动部分。 UART驱动部分依赖于硬件平台,而TTY驱动和具体的平台无关。虽然UART部分依赖于平台,但是不管是哪个硬件平台,驱动的思路都是一致的ÿ…...

(C++20) constinit常量初始化
文章目录 由来constinit 常量初始化常量初始化 ! 初始化常量初始化声明静态存储对象非初始化声明thread_local END 由来 在C多文件编译中会出现一个常见的问题,叫做静态初始化顺序问题。Static Initialization Order Fiasco。 比如现在有两个文件,其中…...

python实现获取aws route53域名信息
最近由于工作原因接触到aws的服务,我需要实时获取所有的域名信息,用于对其进行扫描,因此写了一个自动化爬取脚本 给需要的人分享。 1.基础准备 代码环境:python3 第三方库:boto3 (安装方法pip install…...

Linux_Linux终端常用快捷键
Linux命令行核心常用快捷键是一些在终端中使用的快捷键组合,用于提高命令行操作的效率。下面是这些快捷键的原理详细解释、使用场景解释 Ctrl A :将光标移动到命令行的开头。这个快捷键的原理是发送一个控制序列到终端,告诉终端将光标移动到…...

Neo4j 数据库管理 数据备份与恢复(头歌)
文章目录 第1关:数据备份与恢复任务描述相关知识数据备份数据导入 编程要求测试说明答案测试前准备Cypher 代码数据备份与导入 第1关:数据备份与恢复 任务描述 本关任务:熟练掌握数据备份与恢复。 相关知识 为了完成本关任务,…...

TCP传输的三次握手四次挥手策略
TCP传输的三次握手四次挥手策略如下: 第一次握手:客户端发送一个带有SYN标志的数据包给服务器,并记为SYN_Client。第二次握手:服务器收到SYN_Client后,向客户端发送一个带有SYN和ACK标志的数据包,记为SYN_…...

在gitlab上使用server_hooks
文章目录 1. 前置条件2. Git Hook2.1 Git Hook 分为两部分:本地和远程2.1.1 本地 Git Hook,由提交和合并等操作触发:2.1.2 远程 Git Hook,运行在网络操作上,例如接收推送的提交: 3. 操作步骤3.1 对所有的仓…...

【云原生系列】Kubernetes知识点
目录 概念 基础架构 单master节点 多master节点 组件 Master节点核心组件 其他组件 请求发送流程 插件 核心资源 调度资源 Pod 创建pod组件间调用流程 pod生命周期: 初始化容器 镜像拉取策略 重启策略 钩子函数 探针 探针的实现方式 DownwardAP…...

Hugging-Face报错锦囊(不断更新)
requests.exceptions.SSLError: (MaxRetryError(“HTTPSConnectionPool(host‘huggingface.co’, port443): Max retries exceeded with url: /api/models/bert-base-chinese (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate…...

Redis核心数据结构
目录 五种基础数据结构 string hash list set zset 用zset实现微博热搜 scan遍历 高频问题 五种基础数据结构 string 单个赋值set 批量赋值/取值 msetmget 设置不存在字符串setnx, 如果不存在, 则设置成功返回1, 如果存在返回0, 可以当做分布式锁 删除值 设置过期时…...

Redis 如何批量删除指定前缀的Key
批量删除指定前缀的Key有两中方法,一种是借助 redis-cli,另一种是通过 SCAN 命令来遍历所有匹配前缀的 key,并使用 DEL 命令逐个删除它们。 redis-cli 使用 Redis 自带的 redis-cli 命令行工具,你可以通过以下方式批量删除指定前…...