浏览器详解(四) 渲染
大家好,我是半虹,这篇文章来讲浏览器渲染
1、基本介绍
浏览器是多进程多线程的架构,包括有浏览器进程、渲染器进程、GPU
进程、插件进程等
在上篇文章中我们介绍过浏览器进程,作为浏览器主进程,负责浏览器基本界面的交互和底层功能的执行
在这篇文章中我们来介绍渲染器进程,这是浏览器的内核,也称为渲染进程
渲染进程负责标签页内所发生的事情,主要包括页面渲染、脚本执行、事件处理等
其中包含多个重要的线程以协同工作:
-
GUI
渲染线程:负责页面的渲染,解析 HTML、CSS,构建 DOM、CSSOM,布局和绘制等如果页面要回流或重绘,也由该线程去执行
-
JS
引擎线程:负责解析和执行 JavaScript 脚本,注意JS
引擎线程与GUI
渲染线程互斥 -
事件触发线程: 控制事件循环,并管理事件队列
若当
JS
引擎执行触发异步事件,会将对应的任务交给相应的线程执行处理等到任务完成之后,把任务对应的回调添加到事件队列,等待
JS
引擎处理 -
定时触发线程: 负责处理特定任务,具体来说就是用于
setTimeout
和setInterval
计时等到计时结束,通知事件触发线程,由事件触发线程将对应的回调加入队列
-
异步请求线程: 负责处理特定任务,具体来说就是处理
AJAX
请求等到请求完成,通知事件触发线程,由事件触发线程将对应的回调加入队列
下面我们通过例子,异步请求和定时操作,来说明线程之间如何协同工作

上述多个线程大体上可以分成两组:
- 渲染引擎:其中核心为
GUI
渲染线程 - 脚本引擎:其中核心为
JS
引擎线程,辅助为事件触发线程、定时触发线程、异步请求线程
目前市面主流浏览器使用的渲染引擎和脚本引擎总结如下:
浏览器 | 渲染引擎 | 脚本引擎 |
---|---|---|
Safari | Webkit / WebCore | Webkit / JavaScriptCore |
Chrome | Blink | V8 |
Firefox | Gecko | SpiderMonkey → TraceMonkey → JaegerMonkey |
IE | Trident | Chakra |
Edge | EdgeHTML | Chakra |
在这篇文章中我们主要介绍渲染过程,至于 JS
的解析过程,以后有空的话会专门再讲
好了,下面来正式开始介绍浏览器中的渲染过程
2、渲染流程
渲染引擎渲染页面的过程,也称为关键渲染路径,具体步骤如下:
-
解析 HTML 构建 DOM
具体步骤如下:
转换:从网络或磁盘读取 HTML 文件原始字节,根据文件编码将字节转换为字符串
分词:根据 HTML 规范,将上述字符串切分为不同的标记,如
<html>
、<body>
语法 分析:将上述标记转换为对象,对象中包含语法信息,如属性、属性值等信息
DOM
构建:将上述对象链接在树状的结构中以标识父子和兄弟关系,这个树状结构就是 DOM
需要注意的是:
在读取 HTML 时,DOM 的构建已经开始,可以将上面的步骤理解成是流水线并行
上一个步骤每完成一点,就会将结果传递给下一个步骤,不会等一个步骤完全执行完才进行下一个步骤
关于脚本资源:
当 HTML 解析器遇到
<script>
标签时,会暂停 HTML 的解析,并开始加载、解析和执行 JavaScript这是因为 JavaScript 可能会修改 DOM 的结构,若明确 JavaScript 不会修改 DOM, 那么:
你可以为
<script>
标签加async
属性,这样是异步加载 JavaScript,但是加载完马上就会开始执行也可以为
<script>
标签加defer
属性,这也是异步加载 JavaScript,且等 DOM 构建完才开始执行其实如果 JavaScript 确实要修改 DOM 某节点,那也该将其放到 DOM 的构建之后
否则有些获取元素的 操作可能就不能生效
关于外部资源:
一个网页通常包含多个外部资源,例如图片、CSS、JavaScript、字体等等
在解析 DOM 过程中,会按文档的顺序逐一发起请求 ,但是为了提高效率会同时运行预加载扫描器
预加载扫描器查看已切分的标记,从中寻找资源地址并告知网络线程请求
如此当 HTML解析被 JavaScript 阻塞时,预加载扫描器也能继续请求资源
-
解析 CSS 构建 CSSOM
具体步骤如下:
搜集:从内联样式、内部样式表、外部样式表、浏览器代理样式中,搜集所有样式规则
构建:按上述规则构建 CSSOM 树状结构,其中每个节点表示一个样式规则,包含选择器以及样式声明
匹配:遍历 DOM 节点匹配选择器,并为匹配的节点执行样式设置
计算:计算 DOM 节点的最终样式,这些样式可通过以下接口查看:
window.getComputedStyle()
需要注意的是:
上述匹配步骤,CSS 选择器会从右往左匹配 DOM 节点,举个例子,假设 CSS 选择器为
.nav span
那么匹配之时,首先找到所有
span
节点,然后对每个span
节点,向上找.nav
节点
另外注意的是:
构建 DOM 和构建 CSSOM 是同时进行的,但是这并不意味着二者不会相互影响
因为 CSSOM 构建会阻塞脚本执行,而脚本执行会阻塞 DOM 构建,有一个间接的影响
-
布局 (Layout)
有了 DOM 和 CSSOM 后,需要根据二者构建出渲染树 (RenderObject Tree)
渲染树只会包含可见元素,像 head 节点和 display 为 none 的节点,则不会出现在渲染树中
至此,其实已经知道每个可见节点的样式,接下来需要根据渲染树进行布局计算
即根据盒子模型和视觉格式化模型来计算每个节点在设备视口内的位置以及大小
当页面布局和几何信息发生变化时,浏览器需要重新布局,这个过程被称为回流 (reflow)
具体又可分为全局布局和局部布局,常见的引起回流阶段的操作如下:
- 页面第一次进行渲染
- 窗口的尺寸发生改变
- 增加或删除可见元素
- 元素的位置发生改变
- 元素的大小发生改变
- …
-
绘制 (Paint)
绘制实际上就是遍历渲染树,在屏幕中绘制出对应的节点内容,简单来说就是个像素填充的过程
绘制过程在多个层上完成的,这些层被称为渲染层 (Render Layer)
渲染树中每个节点都是一个渲染对象,处于相同坐标空间 (z 轴) 的渲染对象会合并到同一个渲染层
对于满足层叠上下文条件的渲染对象,浏览器会为其自动创建新的渲染层,常见情况如下:
- 根元素
- 有
mask
属性 - 有
filter
属性 - 有
reflection
属性 - 有
position
属性且值为absolute
、relative
、fixed
、sticky
- 有
backface-visibility
属性且值为hidden
- 有
transform
属性且值不为none
- 有
overflow
属性且值不为visible
- 有
opacity
属性且值小于1
- 对
opacity
、transform
、filter
等属性应用动画
满足上述条件的渲染对象拥有独立的渲染层,但这并不意味着这些渲染对象独享该渲染层
这是因为不满足上述条件的渲染对象将会与第一个拥有渲染层的父元素共用同一个渲染层
当元素样式有变化但不影响布局时,浏览器需要重新绘制,这个过程被称为重绘 (repaint)
具体又可分为全局绘制和局部绘制,常见的引起重绘阶段的操作如下:
- 修改元素
color
- 修改元素
background-color
- …
值得注意的是:回流一定引起重绘,重绘不一定引起回流
-
合成 (Composite)
合成阶段中,多个渲染层按照恰当的重叠顺序进行合并,而后生成位图,最终通过显卡展示在屏幕上
在这过程中,某些渲染层会被浏览器自动提升为合成层 (Compositing Layer), 常见情况如下:
- 有
will-change
属性 - 有
position
属性且值为fixed
- 有
transform
属性且值为translate3d
、translateZ
等 3D 变换 - 是
canvas
、video
、iframe
等元素 - 对
opacity
、transform
、filter
等属性应用动画
每个合成层拥有单独的 Graphics Layer 用于生成位图,并上传到 GPU 对其进行合成,绘制到屏幕上
其它不是合成层的渲染层与第一个拥有 Graphics Layer 的父层级共用
合成层有什么用?答案是硬件加速,即把某些需要频繁回流和重绘的元素单独提升成为合成层
这样不仅可以提高绘制的效率,也能减少这些元素修改时对其它元素影响
例如修改合成层的
transform
时,不会带来回流或重绘,只需要将多个图层再次合并,而后生成位图这样我们可以通过
transform:translate
修改元素位置,通过transform:scale
修改元素大小 - 有
渲染进程的工作对浏览器性能有重要影响,常见渲染优化包括:
- 关键样式资源放在头部加载,善用
preload
、prefetch
- 脚本资源通常放在脚部加载,善用
async
、defer
- 尽量减少回流以及重绘操作,例如 批量修改 DOM 、离线修改 DOM 等等
- 对于画布,常用的技术包括有分层 canvas、离屏 canvas 等等
- 对于动画,使用
requireAnimationFrame
代替setTimeout
- 硬件加速
- …
类似方法有很多,这些都需要在日常开发中不断地积累,并有意识地应用到未来开发中
好啦,本文到此结束,感谢您的阅读!
如果你觉得这篇文章有需要修改完善的地方,欢迎在评论区留下你宝贵的意见或者建议
如果你觉得这篇文章还不错的话,欢迎点赞、收藏、关注,你的支持是对我最大的鼓励 (/ω\)
相关文章:

浏览器详解(四) 渲染
大家好,我是半虹,这篇文章来讲浏览器渲染 1、基本介绍 浏览器是多进程多线程的架构,包括有浏览器进程、渲染器进程、GPU 进程、插件进程等 在上篇文章中我们介绍过浏览器进程,作为浏览器主进程,负责浏览器基本界面的…...

idea新建一个module时,文件夹显示灰色/pom.xml文件显示灰色且中间有条横线
1.问题 2.解决方法 File->Settings->Ignored Files->找到勾选的pom.xml文件,取消勾选,点击ok即可。 3.已解决...

NoSQL数据库(林子雨慕课课程)
文章目录 5.1 NoSQL数据库5.2 NoSQL和关系数据库的比较5.3 四大类型NoSQL数据库5.3.1 键值数据库和列族数据库5.3.2 文档数据库、图数据库、以及不同数据库比较分析 5.4 NoSQL数据库的理论基石CAP理论:BASE理论:Eventual consistency(最终一致…...

模拟器运行在AndroidStudio内部,设置其独立窗口显示
在窗口内部运行 设置成独立窗口 Android Studio->Settings或Preferences->Tools->Emulator->取消勾选Launch in the Running Devices tool window --->点击右下角的OK按钮 ---> 重启Android Studio 再次启动模拟器...

计算机网络 | 体系结构
计算机网络 | 体系结构 计算机网络 | 体系结构概念及功能计算机网络简介计算机网络的功能因特网发展阶段小结 组成与分类计算机网络的组成计算机网络的分类小结 标准化工作及相关组织速率相关性能指标速率带宽吞吐量小结 时延相关性能指标时延时延带宽积往返时延RTT利用率小结 …...

ELK 处理 SpringCloud 日志
在排查线上异常的过程中,查询日志总是必不可缺的一部分。现今大多采用的微服务架构,日志被分散在不同的机器上,使得日志的查询变得异常困难。工欲善其事,必先利其器。如果此时有一个统一的实时日志分析平台,那可谓是雪…...
mac使用python递归删除文件夹下所有的.DS_Store文件
import osfolder_path "yourself file path"for root, dirs, files in os.walk(folder_path):for filename in files:if filename .DS_Store:file_path os.path.join(root, filename)os.remove(file_path)print("delete ok")...

Gitlab+Jenkins自动化部署,解放双手
项目打包 在部署项目前需要对源码进行打包,一个简单的SpringBoot项目默认是打包为jar包,也就是在pom.xml中的<packaging>jar</packaging>方式,当然也会有一些打包成war包方式,使用外置的Tomcat应用服务器部署war包…...
NNDL:作业3
在Softmax回归的风险函数(公式(3.39))中如果加上正则化项会有什么影响? (1) 在 Softmax 回归的风险函数中加入正则化项会对模型的训练产生影响。正则化项的作用是对模型的复杂度进行惩罚,防止过拟合的发生。 (2) 原书公式为: 在加入正则化后损失函数…...
dockers --cap-add 哪些值可以设置
--cap-add 参数可以用于向 Docker 容器添加不同的权限。除了 NET_ADMIN,还有一些其他常用的权限值,包括: SYS_ADMIN:添加系统管理员权限,允许容器内的进程执行系统级别的管理操作,如挂载文件系统、设置时间…...
golang常用库之-HTTP客户端请求库 grequests
文章目录 golang常用库之-HTTP客户端请求库 grequests什么是grequests使用 golang常用库之-HTTP客户端请求库 grequests 什么是grequests 官网:github.com/levigross/grequests A Go “clone” of the great and famous Requests library Go语言的grequests库是一…...

17基于matlab卡尔曼滤波的行人跟踪算法,并给出算法估计误差结果,判断算法的跟踪精确性,程序已调通,可直接运行,基于MATLAB平台,可直接拍下。
17基于matlab卡尔曼滤波的行人跟踪算法,并给出算法估计误差结果,判断算法的跟踪精确性,程序已调通,可直接运行,基于MATLAB平台,可直接拍下。 17matlab卡尔曼滤波行人跟踪 (xiaohongshu.com)...

SpringCloud之Stream框架集成RocketMQ消息中间件
Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架。它可以基于 Spring Boot 来创建独立的、可用于生产的 Spring 应用程序。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三…...

与创新者同行!Apache Doris 首届线下峰会即将开启,最新议程公开!|即刻预约
点击此处 即刻报名 Doris Summit Asia 2023 回顾人类的发展史,地球起源于 46 亿年前的原始星云、地球生命最初出现于 35 亿年前的原始海洋、人类物种诞生于数百万年前,而人类生产力的真正提升源于十八世纪六十年代的工业革命,自此以后&#…...

vue解决:Parsing error: No Babel config file detected for ....
报错信息 Parsing error: No Babel config file detected for C:\Users\Admin\Desktop\shabi\work\src\App.vue. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. 分析错误:没有检测…...

算法题:K 次取反后最大化的数组和(典型的贪心算法问题)
这道题没有看题解,直接提交,成绩超越99.5%,说明思路是优的。就是考虑的情况里面弯弯绕比较多,需要考虑全面一点。(本题完整题目附在了最后面) 具体思路如下: 1、首先排序,然后从最…...
Go语言中向[]byte数组中增加一个元素
要向http.Request的body中添加一个键值对,可以先将其转换为一个map,然后对其进行修改,最后再将其转回为byte数组。 以下是一个示例代码: import ("net/http""io/ioutil""encoding/json" )type Re…...

CSS 布局案例: 2行、多行每行格数不定,最后一列对齐
布局期望的效果如下: 第二行最后一格与第一行最后一格对齐。每行格数不定。自动拉伸填充整个宽度 实现: 一开始打算用display:flex, 自动分散,但是第二行对齐第一行最后一格控制不了。 使用grid fr均分单位控制。 <!DOCTYPE…...

数据结构--算法、数据结构的基本概念
📕参考:王道 一、算法的基本概念 1.程序数据结构算法 2.算法的特性 (1)有穷性 执行有穷步之后结束,且每一步都可在有穷时间内完成。 (2)确定性 (3)可行性 可通过已经实…...

Edge浏览器下载文件被保存为 .crdownload 文件的问题小记
问题 近期使用Edge浏览器下载文件时,文件都被保存为 .crdownload 格式的文件了,不确定从哪个版本开始的。除非下载未完成导致文件不完整,否则不会被保存为 .crdownload 格式的文件;实际上文件已完成了下载,且手工修改…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...

wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...