Renderer进程包含什么
- 主线程
- worker线程(包括web worker和service worker)
- compositor线程
- raster线程
核心工作是将 HTML、 CSS 和 JavaScript 转换成用户可以与之交互的网页。
解析
构造DOM
DOM是浏览器对页面的内部表示,开发者具有可与之交互的API。根据HTML标准,HTML具有很好的容错性。
子资源加载
解析构建DOM时,有个preload scanner,它可以并发运行获取一些外部资源,如图片、CSS和JS。在浏览器进程中向网络线程发送请求。
JS阻止解析
HTML一旦遇到script标签,就停止解析HTML。继而加载解析和执行JS代码。因为可以通过document.write
这样的API修改DOM结构。有一篇很好的关于V8如何执行JS的文章
提示浏览器如何加载资源
如果JS不使用document.write
,可以标记script
为async
或者defer
,浏览器就可以异步加载运行JS代码,不阻止解析。也可以使用javascript module。<link rel="preloa">
是一种告诉浏览器当前导航需要该资源的方式,希望尽快下载。
计算样式
使用CSS可以对页面进行样式化,主线程解析CSS确定每个DOM结点的计算样式。浏览器默认存在一个样式表。
布局
主线程遍历DOM和计算样式,构建布局树,其中包含元素坐标以及边界框大小。并且只包含课件内容。visibility:hidden
位于布局树中,display:none
不位于布局树中。伪元素::before
会包含在布局树,而不在DOM树。
chrome有一个工程师团队负责布局,这是一些工作细节
绘制
该阶段负责判断绘制的顺序。如果设置了z-index
则不能单纯按HTML元素顺序绘制。
主线程遍历布局树,创建paint records
,是绘制过程的一个描述,例如“先画background,然后text,然后rectangle”。类似于JS绘制canvas。
更新渲染pipeline很昂贵
布局树发生变化,绘制顺序也会发生变化。前面的操作会影响后面的操作。在给元素配置动画,浏览器需要在每个帧之间操作动画,如果每一帧都移动物体,动画显得很流畅。但是如果错过中间帧,页面就会janky
。
应用程序运行JS时,动画也可能会被阻塞,因为他们运行在主线程上。从而显得janky
。
可以将JS操作分块。使用requestAnimationFrame
在每一帧运行。也可以在web worker运行JS
合成
浏览器在这个过程开始前已经知道了文档结构,元素样式,页面的几何特征和绘制顺序。将这些信息转换为屏幕上的像素,叫做rasterizing(光栅化)。chrome将页面各部分分层,分别光栅化,然后组合成一个框架,当滚动页面,这些已经光栅化的层组合成一个新的框架。
分层
为了找出元素需要在哪里。主线程遍历布局树创建层树(layer tree),在开发者工具的performance面板中叫做update layer tree。如果有些部分应该是单独的层而没有在单独的层中,可以使用CSS的will-change
属性提示浏览器。
raster和composite脱离主线程
创建层树,确定绘制顺序后,主线程将信息交给compositor线程。compositor线程光栅化每一层。一个层可以像页面那么大,所以compositor将其分成几个tiles,每一个tile因此发送给raster线程,raster线程光栅化每一个tile,存储在GPU内存。
compositor线程可以优先处理不同的raster线程,所以视口附近的东西可以优先光栅化。一个layer也有许多不同分辨率的tillings用于处理zoom-in这样的行为。
一旦tiles光栅化完毕,compositor线程就会收集draw quads来创建一个compositor frame。
draw quads包含一些信息,例如tile在内存中的位置,以及在考虑到页面合成的情况下要绘制tile的页面位置
compositor frame是一个表示页面frame的draw quads集合。
然后通过 IPC 将compositor frame提交到浏览器进程。此时,可以从 UI 线程为浏览器 UI变化添加另一个compositor frame,或者从其他renderer进程为extension添加另一个compositor frame。这些compositor frame被发送到 GPU 在屏幕上显示。如果出现滚动事件,compositor线程将创建另一个compositor frame并发送到 GPU。
compositing的好处是它不需要涉及主线程。compositor线程不需要等待样式计算或 JavaScript 执行。这就是为什么compositing动画被认为是最好的平稳性能。如果布局或者绘制需要再次计算,那么主线程必须参与。