浏览器详解(四) 渲染
大家好,我是半虹,这篇文章来讲浏览器渲染
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 格式的文件;实际上文件已完成了下载,且手工修改…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
