浏览器渲染过程详解

渲染流程

  1. 浏览器通过网络请求后获取 html 数据,通过 tcp 传给浏览器进程,然后浏览器进程再传递给渲染器进程
  2. DOM - DOM 结构: 主线程将 html 解析构造 DOM
  3. style - 样式: 主线程解析页面的 CSS 从而确定每个 DOM 节点的计算样式(computed style)。
  4. layoutTree - 布局树: dom+style 根据 dom 树和样式生成 layoutTree
  5. paint - 绘制: 通过遍历 Layout Tree 生成绘制顺序表
  6. laryer - 布局: 主线程将 layoutTree 和绘制信息表传给合成器线程
  7. 合成器线程: 将得到的信息分图层分成更小的图块
  8. 栅格线程: 将更小的图块进行栅格化 raster,返还给合成器线程 draw quads 图块信息,存储在 GPU
  9. 合成线程会收集图块上面叫做绘画四边形(draw quads)的信息来构建一个合成帧(compositor frame)。
  10. 合成线程就会通过 IPC 向浏览器进程(browser process)提交(commit)一个渲染帧。
  11. 浏览器进程收到一帧的图像后传给 GPU 进行渲染

非快速滚动区域 - non-fast scrollable region

当一个页面被合成的时候,合成线程会将页面那些注册了事件监听器的区域标记为“非快速滚动区域”(Non-fast Scrollable Region)。当用户事件发生在这些区域时,合成线程会将输入事件发送给主线程来处理。如果输入事件不是发生在非快速滚动区域,合成线程就无须主线程的参与来合成一个新的帧。

问题

body 元素绑定了事件监听器后其实是将整个页面都标记为一个非快速滚动区域,这就意味着即使你页面的某些区域压根就不在乎是不是有用户输入,当用户输入事件发生时,合成线程每次都会告知主线程并且会等待主线程处理完它才干活。因此这种情况下合成线程就丧失提供流畅用户体验的能力了(smooth scrolling ability)。

解决办法

可以为事件监听器传递 passive:true 选项。 这个选项会告诉浏览器您仍要在主线程中侦听事件,可是合成线程也可以继续合成新的帧。

查找事件的目标对象(event target)

当合成线程向主线程发送输入事件时,主线程要做的第一件事是通过命中测试(hit test)去找到事件的目标对象(target)。具体的命中测试流程是遍历在渲染流水线中生成的绘画记录(paint records)来找到输入事件出现的 x, y 坐标上面描绘的对象是哪个。

相关概念

DOM 对象

既是浏览器对当前页面的内部表示,也是 Web 开发人员通过 JavaScript 与网页进行交互的数据结构以及 API

光栅化(rasterizing)

将以上文档结构,元素的样式,元素的几何信息以及它们的绘画顺序转化为显示器的像素的过程

绘画四边形

包含图块在内存的位置以及图层合成后图块在页面的位置之类的信息。

合成帧

代表页面一个帧的内容的绘制四边形集合。

参考