浏览器详解(四) 渲染

大家好,我是半虹,这篇文章来讲浏览器渲染


1、基本介绍

浏览器是多进程多线程的架构,包括有浏览器进程、渲染器进程、GPU 进程、插件进程等

在上篇文章中我们介绍过浏览器进程,作为浏览器主进程,负责浏览器基本界面的交互和底层功能的执行

在这篇文章中我们来介绍渲染器进程,这是浏览器的内核,也称为渲染进程


渲染进程负责标签页内所发生的事情,主要包括页面渲染、脚本执行、事件处理等

其中包含多个重要的线程以协同工作:

  1. GUI 渲染线程:负责页面的渲染,解析 HTML、CSS,构建 DOM、CSSOM,布局和绘制等

            如果页面要回流或重绘,也由该线程去执行

  2. JS  引擎线程:负责解析和执行 JavaScript 脚本,注意  JS 引擎线程与 GUI 渲染线程互斥

  3. 事件触发线程: 控制事件循环,并管理事件队列

            若当 JS 引擎执行触发异步事件,会将对应的任务交给相应的线程执行处理

            等到任务完成之后,把任务对应的回调添加到事件队列,等待 JS 引擎处理

  4. 定时触发线程: 负责处理特定任务,具体来说就是用于 setTimeoutsetInterval 计时

            等到计时结束,通知事件触发线程,由事件触发线程将对应的回调加入队列

  5. 异步请求线程: 负责处理特定任务,具体来说就是处理 AJAX 请求

            等到请求完成,通知事件触发线程,由事件触发线程将对应的回调加入队列


下面我们通过例子,异步请求和定时操作,来说明线程之间如何协同工作

线程协作

上述多个线程大体上可以分成两组

  1. 渲染引擎:其中核心为 GUI 渲染线程
  2. 脚本引擎:其中核心为  JS  引擎线程,辅助为事件触发线程、定时触发线程、异步请求线程

目前市面主流浏览器使用的渲染引擎和脚本引擎总结如下:

浏览器渲染引擎脚本引擎
SafariWebkit / WebCoreWebkit / JavaScriptCore
ChromeBlinkV8
FirefoxGeckoSpiderMonkeyTraceMonkeyJaegerMonkey
IETridentChakra
EdgeEdgeHTMLChakra

在这篇文章中我们主要介绍渲染过程,至于 JS 的解析过程,以后有空的话会专门再讲

好了,下面来正式开始介绍浏览器中的渲染过程


2、渲染流程

渲染引擎渲染页面的过程,也称为关键渲染路径,具体步骤如下:

  1. 解析 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 阻塞时,预加载扫描器也能继续请求资源


  2. 解析 CSS 构建 CSSOM

    具体步骤如下:

    搜集:从内联样式、内部样式表、外部样式表、浏览器代理样式中,搜集所有样式规则

    构建:按上述规则构建 CSSOM 树状结构,其中每个节点表示一个样式规则,包含选择器以及样式声明

    匹配:遍历 DOM 节点匹配选择器,并为匹配的节点执行样式设置

    计算:计算 DOM 节点的最终样式,这些样式可通过以下接口查看:window.getComputedStyle()


    需要注意的是:

    上述匹配步骤,CSS 选择器会从右往左匹配 DOM 节点,举个例子,假设 CSS 选择器为 .nav span

    那么匹配之时,首先找到所有 span 节点,然后对每个 span 节点,向上找 .nav 节点


    另外注意的是:

    构建 DOM 和构建 CSSOM 是同时进行的,但是这并不意味着二者不会相互影响

    因为 CSSOM 构建会阻塞脚本执行,而脚本执行会阻塞 DOM 构建,有一个间接的影响

    线程协作
  3. 布局 (Layout)

    有了 DOM 和 CSSOM 后,需要根据二者构建出渲染树 (RenderObject Tree)

    渲染树只会包含可见元素,像 head 节点和 display 为 none 的节点,则不会出现在渲染树中


    至此,其实已经知道每个可见节点的样式,接下来需要根据渲染树进行布局计算

    即根据盒子模型和视觉格式化模型来计算每个节点在设备视口内的位置以及大小


    当页面布局和几何信息发生变化时,浏览器需要重新布局,这个过程被称为回流 (reflow)

    具体又可分为全局布局和局部布局,常见的引起回流阶段的操作如下:

    • 页面第一次进行渲染
    • 窗口的尺寸发生改变
    • 增加或删除可见元素
    • 元素的位置发生改变
    • 元素的大小发生改变

  4. 绘制 (Paint)

    绘制实际上就是遍历渲染树,在屏幕中绘制出对应的节点内容,简单来说就是个像素填充的过程

    绘制过程在多个层上完成的,这些层被称为渲染层 (Render Layer)


    渲染树中每个节点都是一个渲染对象,处于相同坐标空间 (z 轴) 的渲染对象会合并到同一个渲染层

    对于满足层叠上下文条件的渲染对象,浏览器会为其自动创建新的渲染层,常见情况如下:

    • 根元素
    • mask 属性
    • filter 属性
    • reflection 属性
    • position 属性且值为 absoluterelativefixedsticky
    • backface-visibility 属性且值为 hidden
    • transform 属性且值不为 none
    • overflow 属性且值不为 visible
    • opacity 属性且值小于 1
    • opacitytransformfilter 等属性应用动画

    满足上述条件的渲染对象拥有独立的渲染层,但这并不意味着这些渲染对象独享该渲染层

    这是因为不满足上述条件的渲染对象将会与第一个拥有渲染层的父元素共用同一个渲染层


    当元素样式有变化但不影响布局时,浏览器需要重新绘制,这个过程被称为重绘 (repaint)

    具体又可分为全局绘制和局部绘制,常见的引起重绘阶段的操作如下:

    • 修改元素 color
    • 修改元素 background-color

    值得注意的是:回流一定引起重绘,重绘不一定引起回流


  5. 合成 (Composite)

    合成阶段中,多个渲染层按照恰当的重叠顺序进行合并,而后生成位图,最终通过显卡展示在屏幕上

    在这过程中,某些渲染层会被浏览器自动提升为合成层 (Compositing Layer), 常见情况如下:

    • will-change 属性
    • position 属性且值为 fixed
    • transform 属性且值为 translate3dtranslateZ 等 3D 变换
    • canvasvideoiframe 等元素
    • opacitytransformfilter 等属性应用动画

    每个合成层拥有单独的 Graphics Layer 用于生成位图,并上传到 GPU 对其进行合成,绘制到屏幕上

    其它不是合成层的渲染层与第一个拥有 Graphics Layer 的父层级共用


    合成层有什么用?答案是硬件加速,即把某些需要频繁回流和重绘的元素单独提升成为合成层

    这样不仅可以提高绘制的效率,也能减少这些元素修改时对其它元素影响

    例如修改合成层的 transform  时,不会带来回流或重绘,只需要将多个图层再次合并,而后生成位图

    这样我们可以通过 transform:translate 修改元素位置,通过 transform:scale 修改元素大小


渲染进程的工作对浏览器性能有重要影响,常见渲染优化包括:

  1. 关键样式资源放在头部加载,善用 preloadprefetch
  2. 脚本资源通常放在脚部加载,善用 asyncdefer
  3. 尽量减少回流以及重绘操作,例如 批量修改 DOM 、离线修改 DOM 等等
  4. 对于画布,常用的技术包括有分层 canvas、离屏 canvas 等等
  5. 对于动画,使用 requireAnimationFrame 代替 setTimeout
  6. 硬件加速

类似方法有很多,这些都需要在日常开发中不断地积累,并有意识地应用到未来开发中



好啦,本文到此结束,感谢您的阅读!

如果你觉得这篇文章有需要修改完善的地方,欢迎在评论区留下你宝贵的意见或者建议

如果你觉得这篇文章还不错的话,欢迎点赞、收藏、关注,你的支持是对我最大的鼓励 (/ω\)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/130509.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java 进阶篇】CSS盒子模型详解

CSS盒子模型是网页布局的基础之一&#xff0c;它定义了HTML元素在页面上的占用空间和相互关系。理解CSS盒子模型对于构建各种类型的网页布局至关重要。在本文中&#xff0c;我们将深入探讨CSS盒子模型的各个方面&#xff0c;包括盒子模型的概念、属性和如何使用它们来控制元素的…

2023年山东省安全员C证证考试题库及山东省安全员C证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年山东省安全员C证证考试题库及山东省安全员C证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大…

/lib64/libstdc++.so.6: version `GLIBCXX_3.4.21‘ not found (required by

在某项目中遇到下面的错误&#xff0c; ./model2trt_v2: /lib64/libstdc.so.6: version GLIBCXX_3.4.21 not found (required by ./model2trt_v2) ./model2trt_v2: /lib64/libstdc.so.6: version GLIBCXX_3.4.21 not found (required by ../../../lib/linux_lib/libcuda_utils…

爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会

标题:爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会 网址:https://fgw.sh.gov.cn/fgw-interaction-front/biz/projectApproval/home MD5加密:ca7f5c978b1809d15a4b228198814253 需求文档 采集数据如下所示: 解决反爬思路 这里只提供解决思路,解决反爬,…

远程发送剪切板,屏幕截图

使用场景 线上答题时一般有录屏&#xff0c;局域网内可发送内容到电脑上剪切板&#xff0c;电脑上直接CtrlV双机位看不到屏幕是可以远程截屏 下载 访问地址下载程序&#xff1a;https://gitee.com/guzhengchang/shared-clipboard/releases/tag/v0.2 双击前面下载的程序&am…

系统打印服务已关闭,竟然是它的问题!

故障现象&#xff1a; 一台电脑不能打印文件&#xff0c;一点打印就弹出对话框提示打印服务已关闭。手动开启打印服务后&#xff0c;大约不到1分钟打印服务又自动关闭了。 故障检修&#xff1a; 电脑重新启动后再次重启打印服务&#xff0c;打印服务依然还是会自动关闭。估计是…

docker搭建jenkins

1.拉取镜像 docker pull jenkinsci/blueocean2.启动容器 docker run -d -u root -p 8666:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime --name MyJenkins jenkinsci/blueocean3.访问ip:port,就能访问了 4.docker logs 容器…

面试总结-Redis篇章(十二)——Redis是单线程的,为什么还那么快

Redis是单线程的&#xff0c;为什么还那么快 Redis是单线程的&#xff0c;为什么还那么快什么是IO多路复用 阻塞IO非阻塞IOIO多路复用 Redis是单线程的&#xff0c;为什么还那么快 Redis是纯内存操作&#xff0c;执行速度非常快采用单线程&#xff0c;避免不必要的上下文切换可…

javaScript:什么是事件对象?事件原对象?如何获取坐标点?

目录 前言 事件对象&#xff08;***重要***&#xff09; 事件对象的常见用处 相关代码 事件原对象 获取事件源对象的方式 获取坐标点 clientX clientY&#xff08;常用&#xff09; screenX screenY pageX pageY 兼容写法 &#xff08;ie8以下&#xff09; 其他坐标…

想要开发一款游戏, 需要注意什么?

开发一款游戏是一个复杂而令人兴奋的过程。游戏开发是指创建、设计、制作和发布电子游戏的过程。它涵盖了从最初的概念和创意阶段到最终的游戏发布和维护阶段的各个方面。 以下是一些需要注意的关键事项&#xff1a; 游戏概念和目标&#xff1a; 确定游戏开发的核心概念和目标…

数据结构与算法设计分析——贪心算法的应用

目录 一、贪心算法的定义二、贪心算法的基本步骤三、贪心算法的性质&#xff08;一&#xff09;最优子结构性质&#xff08;二&#xff09;贪心选择性质 四、贪心算法的应用&#xff08;一&#xff09;哈夫曼树——哈夫曼编码&#xff08;二&#xff09;图的应用——求最小生成…

剪切板中,经常用到的gpt编程提问

/data/user/0/org.qpython.qpy/files/bin/qpy thon3.sh "/storage/emulated/0/qpython/评论 截图问题1.矩阵2.1.2.1空行问题1.4.5.py" && exit .1.2.1空行问题1.4.5.py" && exit < 时间戳&#xff1a; 时间戳&#xff1a; ("…