# 三.同步异步编程
# 页面渲染原理
一个页面展示在用户面前,简单来说,会经历 5 个步骤。
1.JavaScript:执行 js 逻辑,修改 DOM,修改 CSS 等。
2.Style:计算样式。
3.Layout:在知道对一个元素应用那些规则之后,浏览器即可开始计算它要占据的空间大小及其在屏幕的位置。这个步骤,就是我们常说的重排。
4.Paint:绘制是填充像素的过程。它涉及绘出文本、颜色、图像、边框和阴影,基本上包括元素的每个可视部分。绘制一般是在多个表面(通常称为层)上完成的。这个步骤,即使我们常说的重绘。
5.Composite:渲染层合并,由上一步可知,对页面中 DOM 元素的绘制是在多个层上进行的。在每个层上完成绘制过程之后,浏览器会将所有层按照合理的顺序合并成一个图层,然后显示在屏幕上。
在浏览器器中,页面的渲染由浏览器的渲染进程完成,而渲染进程中,包含了主线程,worker 线程,Compositer 线程,Raster 线程。上述 5 个过程中,前 4 个过程,都由主线程完成,最后一个步骤,主要有 Raster 线程、Compositer 线程完成。
# JavaScript、Style、Layout
像素管道中的前三个步骤,JavaScript、Style 两个步骤如下:
接着是 Layout,浏览器遍历 render tree 的每一个节点,计算其确切的位置和大小。最终形成一个 Layout Tree.
# Paint
在 Paint 之前,浏览器会根据 Layout Tree,确切需要绘制的对象的层级,我们可以把这个层级叫做渲染层
,最终生成 Layout Tree。这个阶段被称作:Update Layer Tree
在 Paint 这个阶段,浏览器会根据Layout Tree
,生成 Paint Records.
Paint Records 就是描述先画什么,再画什么的记录,跟我们写 canvas 代码时很像。Paint Records 是根据渲染层划分的。
尽管生成了 Paint Records,真正的绘制并不是 Paint 这个阶段完成的,而是在 Composite 阶段由 Raster 线程完成的。
# Composite
经过之前的几个步骤,浏览器主线程已经将页面的内容分成了若干渲染层。为了提升性能,某些特定的渲染层,会被提升为合成层
。我们可以通过下面两个 css 属性,将某个元素强制提升为合成层:
will-change:transform;
//或者
transform:translateZ(0)
2
3
主线程在处理完所有的数据后,会把数据提交到 Compositer 线程。Compositer 线程会利用 Raster 线程来做光栅处理,并将处理好的内容存入内存中。随着 Compositer 线程完成渲染层合成操作,扔给 GPU,页面最终被渲染到屏幕上。
可以通过 Chrome 开发者工具中的 Layer 来查看合成层。
# 其他像素管道
上文中的像素管道共有 5 个步骤。不一定每帧都总是会经过管道每个部分的处理。实际上,不管是使用 JavaScript、CSS 还是网络动画,在实现视觉变化时,管道针对指定帧的运行还有其他两种方式:
- 第一种就是我们所说的页面没有进行重排,值进行了重绘;
- 第二种就是页面即没有进行重排,也没有进行重绘
- 最后的这种运行方式开销最小,适合于页面上的动画效果。