Explore the secrets of the browser rendering

(To the front-end Daquan starred enhance front-end skills )

Author: Front Taoyuan number of public / peach Weng

Foreword

Cause this is, there are small operators with my sister a feedback page Caton powerful. Heart suddenly I thought, yeah mom bug will not have it, the panic panic. Then open their own page, not card ah, a smooth xx, certainly she made a mistake. He took to teach her how to properly use the computer's idea of self-confidence I went downstairs and opened the pages of confidence on her computer, I slip, I slip, I slip again. woc, page Why do not move ah, woc, computers are stuck up. ? ? ? What happens, then there are other operational feedback on the air is not Caton. Page decline Why Caton? Why reflected in the mbp and mba different? All this is exactly where the problem into the sky? Please bosses with these two issues to look down, I will step by step to uncover the veil browser rendering.

First on Photo to let everyone feel the fear of being dominated. Note that the GPU process memory space occupied 10.9 GB.

On mbp

Knowledge base

I want to get to know the following to say, first of all you need to know the relationship between architecture and graphics, GPU, and screen resolution of modern browsers. Of course, even if these do not understand, then you can also look down, I will simply talk about, hee hee hee.

Modern browsers architecture

And because there is no specification, the major browser vendors design their own architecture is not the same (but very much the same), I will take the chrome browser, for example talk about chrome design.

chrome browser from the original single-process to today's multi-process architecture. We can see from the chart above I made the browser include: a browser process, a process GPU, a network process, multiple processes and multiple rendering plug-in process.

The rendering process

To understand the architecture of the browser above, let's talk about today's hero rendering process on how to between multi-process browser is in line with the last show content on the screen, behind this record will be writing articles. Now we talk about the rendering process thing.

Rendering pipeline

Chronologically rendered can be divided into the following sub-stages: constructing a DOM tree, computing style, layout, delamination, drawing, block, rasterization, synthesis . Something a little more, in order to quickly remember and understand, need to focus on each sub-phase input and output, and what had been done deal.

Also you need to understand the rendering process several threads. It comprises a main thread (main thread), the working thread (work thread), synthetic thread (compositor thread) and rasterization thread (Thread Raster) . Later will summarize the specific features of these threads, we look at the overall rendering process.

Build a DOM tree

Build a DOM tree

DOM tree is what I believe we all know, I do not a BB. Because the browser can not directly understand and use html file, so it is necessary to html files into the browser can understand the structure of the DOM tree.

网页中常常包含图片、css、js 等资源文件,这些资源浏览器会去各种渠道获取(缓存、网络下载等)。在构建 DOM 树的时候主线程会去请求他们,相关资源会通过进程之间的通信(IPC)通知网络进程去下载这些资源。在遇到 <script> 标签的时候,解析 DOM 树的工作会暂停,等 js 代码执行完毕之后在去重新解析 DOM 树。

总结一下构建 DOM 树子阶段的输入、输出以及操作过程:

  • 输入:html 文件

  • 输出:DOM 树

  • 操作过程:解析 html 结构为浏览器可以理解的 DOM 树结构,期间会去下载次级资源以及执行 js 代码。

样式计算

样式计算是为了获取每个节点的样式,其主要分为三步来完成。

样式计算

首先和解析 DOM 树一样,浏览器是无法理解 css 代码的,需要将 css 文件转成浏览器可以理解的数据结构 styleSheets具体 styleSheets 是什么样的结构这里我们就不去重点了解了,只需要了解到主进程会将 css 代码转成浏览器可以理解的结构,这个结构支持查询和修改。可以在开发者工具上通过 document.styleSheets 打印出来。

为了适配多端样式,我们可能使用的是 rem、vh 等 css 代码。这些属性值不容被渲染引擎理解,所以需要将这些不是标准化的样式转为标准样式。比如 rem 转成 px、bule 转成 rgba 等。

我们获取到标准化后的样式表,最后就是计算每个节点的样式了。这一步骤涉及到 css 的继承规则和层叠规则。有些属性是可以被子元素继承的,有些属性是会覆盖前面的样式。这一块也不多做讨论了。

总结一下样式计算子阶段的输入、输出和操作过程:

  • 输入:css 样式文件

  • 输出:对应每个 DOM 的样式

  • 操作过程:进行了三个操作,包括:转成浏览器可以理解的 styleSheets、将 css 转成标准化的样式、最后是计算每个节点的样式。

布局阶段

想要渲染一个完整的页面,仅知道 DOM 树和 DOM 树元素的样式还是不够的,我们还需要知道 DOM 树中元素的位置。

布局阶段

同样的布局这个子阶段也分为两个过程操作,分别是合成布局树和计算节点位置。

布局树和 DOM 树类似,不过布局树上只包含会显示的节点内容,不包含如  等元素。也不包含 display: none 样式的元素。只包含可见节点有了一颗完成的布局树,主线程会计算出每个元素的位置信息以及盒子大小。

总结一下布局阶段子阶段的输入、输出和操作过程:

  • 输入:css 样式表、DOM 树

  • 输出:布局树

  • 操作过程:合成布局树、计算节点位置

分层

有了布局树,计算出了每个节点的位置。那么下面是不是进行绘制了呢?答案是否定的,因为页面有很多复杂的效果,比如滑动、z-idnex 等。为了更好的实现这些效果,渲染引擎主线程还需要为特定的阶段生成专用的图层,并生成一颗对应的图层树

分层

分层这一步其实没什么好解释了,唯一需要了解的是哪些元素会被单独分层。布局树和图层树并不是一一对应的关系,不是每个布局树的节点都会生成一个单独的图层树节点。如果一个节点没有对应的层,那么这个节点就从属于父节点的图层那么哪些操作会让节点生成一个单独的图层呢?接着往下面看。

1)拥有层叠上下文属性的元素会单独生成一个图层。

浏览器是一个二维的概念,但是层叠上下文可以让元素具有三维的概念。比如 css 属性中的 z-index、position、css 滤镜等。

  • 3D 或透视变换的 css 属性

  • 使用加速视频解码的 video 元素

  • canvas 元素

  • opacity 属性

2)需要裁剪的地方也会单独生成一个图层

裁剪就是需要滚动的地方,里面内容会单独生成一个图层。如果有滚动条,滚动条也会单独生成一个图层。(所以想一想我那个性能很差的页面有多少个图层?手动狗头)

总结一下布局阶段子阶段的输入、输出和操作过程:

  • 输入:布局树

  • 输出:图层树

  • 操作过程:为特定的节点生成单独的图层、并将这些图层合成图层树

图层绘制

在完成图层树的构建之后,渲染引擎主线程会对每个图层进行绘制。这里说的绘制不是真正的绘制画面,而是生成一个绘制指令列表。

图层绘制

如果我们要在白纸上绘制一些东西,比如黄底、白圆、黑字的一个图案。通常我们会把操作分解成几步来完成:

  • 我们会先在白纸上涂上黄色的底。

  • 然后我们会在黄底上画一个白色的圆。

  • 最后我们会在白色圆上画出黑色的字。

渲染引擎的图层绘制和这个类似,会把每一个图层的绘制拆分成很多的绘制指令

总结一下布局阶段子阶段的输入、输出和操作过程:

  • 输入:图层树

  • 输出:每个图层的绘制指令

  • 操作过程:将每个图层的绘制拆分成多个绘制指令,传给合成线程

栅格化

绘制列表只是用来生成记录绘制指令的列表,实际的绘制操作是有渲染进程的合成线程来执行的。

栅格化

绘制指令生成之后,渲染进程主线程会将绘制指令发送给合成线程,由合成线程来完成最后的绘制工作。合成线程会将图层划分为图块简单解释下图块是什么,浏览器的视口内容是有限的,有些图层可能非常大。渲染进程不会把该图层的所有内容都渲染出来,而是会将这些图层划分为一个一个小的图块栅格化子进程会将视口区域内的图块转化为位图(磁贴),并将这位存入 GPU 显存中。GPU 操作是在 GPU 进程中,所以渲染进程会通过 IPC 通信协议来通知 GPU 进程来进行操作。

总结一下布局阶段子阶段的输入、输出和操作过程:

  • 输入:绘制指令列表、图层树。

  • 输出:位图

  • 操作过程:将图层划分为图块,将图块转换成位图。

合成和显示

等所有图块都被栅格化,合成线程会收集位图信息来创建合成帧合成帧随后会通过 IPC 协议将消息传给浏览器主进程浏览器主进程收到消息后,会将页面内容绘制到内存中,最后再将内存显示在屏幕上。

总结

到这里,我们整个浏览器的渲染进程也就讲完了。下面我们通过一张图来总结一下渲染过程中,浏览器各进程各线程是如何工作的。

总结
  • 主线程将 html 文件转化为浏览器能够读懂的 DOM 树结构。其中会通过网络进程加载次级资源,遇到 js 会停止构建 DOM 树,并执行 js。

  • 主线程将 css 文件转化为浏览器能够读懂的 styleSheets 结构,并将其中的属性标准化,最后计算每个节点的样式

  • 主线程通过得到的 DOM 树和 styleSheets 样式表合成一颗布局树并计算每个节点的具体位置

  • 主线程通过得到的布局树进行图层分层并得到一个图层树

  • 主线程通过分层树对每一个图层分解绘制指令,得到一个绘制指令列表

  • 合成线程对图层进行分块处理,并对视口区域内的图块进行位图转换,将得到的结果通过 GPU 进程存入到 GPU 显存中。

  • 合成线程收集位图信息创建合成帧,并将消息通过 IPC 协议传给浏览器主进程,主进程收到消息后,会将页面内容绘制到内存中,最后再将内存显示在屏幕上。

上面已经讲完了浏览器整个渲染流程,我们来讲讲产生这个例子中产生卡顿的原因。通常情况下图层是有助于性能的,但是创建的每一层都需要内存和管理,而这些并不是免费的。事实上,在内存有限的设备上,对性能的影响可能远远超过创建层带来的任何好处。每一层的纹理都需要上传到 GPU,使 CPU 与 GPU 之间的带宽、GPU 上可用于纹理处理的内存都受到进一步限制。

屏幕分辨率、显卡等关系

讲完了渲染流程,也找到了页面卡顿的原因。但是我们还是不知道为何页面在 mbp 和 mba 上有差异。这就是接下来我们要讲的内容了。

我们需要了解几个概念:屏幕尺寸、分辨率、屏幕像素密度

  • 屏幕尺寸,单位通常是英寸,其大小是显示器的对角线长度。

  • 分辨率也就是屏幕上由多少个像素组成,mbp 的屏幕分辨率是 2560 * 1600,也就是在横向的宽度上有 2560 个像素,竖向的高度上有 1600 个像素。

  • 屏幕像素密度(ppi ),每英寸屏幕有多少个像素。

mbp 的屏幕分辨率是 2560 * 1600,mba 的屏幕分辨率是 1440 * 900。这样算下来 mbp 有 409600 个像素,mba 有1296000 个像素。显卡压力会小很多,内存占用也会更少。再有因为整个布局是 table 布局,每次滑动都会导致整个 table 表格回流,导致整个 GPU 内存飙升。

总结

至此整个问题就全部解决、全部了解清楚了。其实刚开始就把这个问题解决了,但是其中很多东西一直都不怎么了解,趁着这次机会把整个过程都了解清楚。其实像我们这种做开发的人,就是要有一种死钻牛角的精神,不能把问题解决了就行了,更要了解其中的原理,为什么会这样。期间我也有想放弃不整了,还是在小伙伴的帮助下完成这次的探寻之旅。在毕业初期能够遇到一个和自己讲的来话的学长真的能给自己很大的帮助。

共勉。

最后放一张解决了问题后的图。

解决后

参考链接

  • 极客时间《浏览器工作原理与实践》第5、6讲

  • https://zhuanlan.zhihu.com/p/47407398

  • https://developers.google.com/web/fundamentals/performance/rendering/stick-to-compositor-only-properties-and-manage-layer-count

  • https://my.oschina.net/u/2282680/blog/805130

  • https://www.zhihu.com/question/268016229

  • https://www.jianshu.com/p/c3387bcc4f6e

推荐阅读

(点击标题可跳转阅读)

烧脑!JS+Canvas 带你体验「偶消奇不消」的智商挑战

Google 员工吐槽 TypeScript :类型检查不太好

How to make your JS written more beautiful

I think this paper help you? Please share with more people

Watch "front-end Daquan" Starred, improve front-end skills

Good article, I look at ❤️

Released 3363 original articles · won praise 36 · Views 140,000 +

Guess you like

Origin blog.csdn.net/cpongo9/article/details/103351144