发送&接收信息

浏览器进程的UI线程捕获输入内容(网址),并启动网络线程进行DNS域名解析获取内容;网络线程准备好数据后通知UI线程进行下一步处理,之后UI线程会启动一个渲染进程并通过IPC管道将数据发送给它


解析HTML

当数据从UI线程发送到渲染器进程后,渲染器的主线程开始工作,渲染器进程内部包含主线程、工作线程、合成器线程和光栅线程;主线程开始对HTML数据进行解析,构建出DOM树;同时解析CSS并确定每个DOM节点的计算样式.


布局

目前渲染器进程只知道DOM结构和节点样式,但是缺少每个DOM的xy坐标,所以这个阶段主线程会遍历DOM树和计算好的CSS样式生成Layout Tree

DOM TreeLayout 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 标签