发送&接收信息
浏览器进程的UI线程捕获输入内容(网址),并启动网络线程进行DNS域名解析获取内容;网络线程准备好数据后通知UI线程进行下一步处理,之后UI线程会启动一个渲染进程并通过IPC管道将数据发送给它
解析HTML
当数据从UI线程发送到渲染器进程后,渲染器的主线程开始工作,渲染器进程内部包含主线程、工作线程、合成器线程和光栅线程;主线程开始对HTML数据进行解析,构建出DOM树;同时解析CSS并确定每个DOM节点的计算样式.
布局
目前渲染器进程只知道DOM结构和节点样式,但是缺少每个DOM的xy坐标,所以这个阶段主线程会遍历DOM树和计算好的CSS样式生成Layout Tree
DOM Tree
与Layout Tree
并不是一一对应,因为一些特殊的原因会导致两者存在一定的差异;
绘制
拥有了DOM、样式、布局仍然不足以渲染页面,目前还缺少层级关系,也就是z-index
;在这个过程中主线程会遍历Layout Tree
按照先背景,后文字,再矩形
的规则生产一个绘制记录表(Paint Recoed);
合成
当知道了DOM、样式、布局、绘制顺序后,浏览器会将一个页面的各个部分分层并且单独光栅化它们,然后再合成器线程单独合成页面
分层
主线程会遍历Layout Tree
生产Layer Tree
,当确定好Layer Tree
和绘制顺序后,主线程将它们交给合成器线程,合成器线程光栅化每一层,之后将每一层分成多个图块并发送给光栅线程,光栅线程光栅化每个图块并将它们存储在GPU内存里;
当图块栅格化完成后,合成器线程会收集图块信息(draw quads)生成合成器帧(compositor frame);之后通过IPC将合成器帧发送给浏览器进程,浏览器进程再将它们发送给GPU以显示在屏幕上;
减少重排和重绘
- 使用 transform 替代 top
- 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发重排(改变了布局)
- 不要把节点的属性值放在一个循环里当成循环里的变量
- 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
- 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
- CSS 选择符从右往左匹配查找,避免节点层级过多
- 将频繁重绘或者重排的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层。设置节点为图层的方式有很多,我们可以通过以下几个常用属性可以生成新图层:will-change、video、iframe 标签