Life of a Pixel 原本是 Chromium 团队在入职培训时的培训资料,其目的是为了让新入职的同事可以从大致上快速的了解 Chromium 的架构,而不是纠结于代码逻辑。如今该团队正式将其发布,也是为了对于此感兴趣的工程师可以快速的了解项目,参与项目的开发协做。本视频的内容,从宏观上来讲,就是本演讲的题目 Life of a Pixel,直译就是一个像素点的一辈子,表示该演讲做者但愿观众可以在视频结束后了解,前端的工程师所完成的代码,是如何经过浏览器,变为一个又一个的像素点,以及像素点是如何更新和毁灭的。前端
web content (代码) ➡️ magic (渲染) ➡️pixels (像素)python
浏览器真正渲染的内容在红框内,以外的都是非渲染的部分。渲染的引擎能够看作是一个黑箱,在 Chromium 中,咱们把它称为 Blink。git
同时,在渲染时,咱们须要调用图像处理的底层 API 去进行渲染,对于此,有官方的统一标准就是 openGL,可是,对于 Windows,可能还须要转化为 DirectX。对于此,团队正在开发一个新项目名为 Vulkan,为了进行统一化。固然,这种底层的 API 并不能读懂咱们的 HTML 和 CSS,它们只能作一些简单得图像绘制,诸如画一些多边形这种操做。web
因此,咱们再梳理一遍流程。总的来讲就是咱们要将 web content 转化为对于的图像处理的 API,在电脑屏幕上进行绘制。在这个过程当中,为了更好地将已经渲染的图像更新,咱们要设计一种数据结构,可以帮助咱们更新这个页面的结构与内容和页面样式。这些更新就包括咱们熟知的 JavaScript API,用户在输入框输入,异步加载,动画,卷轴移动,页面缩放。后端
HTML 的结构,是一种自然的语义化的继承式的结构。语义化是标签所带来的,集成式是树状结构所带来的。咱们能够将 HTML 看作输入进行解析,成为一颗咱们熟知的 DOM 树。很好的诠释了父子间,兄弟间的关系。咱们也能够很直观的从 JavaScript 所暴露出的 DOM API 中发现。浏览器
在 CSS 解析时,解析器会将每个选择器所选择的 CSS 属性名和属性值保存,做为 map,同时视频中说起,CSS 属性名是由 C++ 进行生成的,该 C++ 文件在构建时由 python 脚本自动生成。下一步,称为重计算(recalc),对于全部产生的属性,咱们会计算它们的叠加和,做为每个 DOM 元素的每个属性的值,这个值咱们也称为计算值。也就是最终渲染的结构。这个属性值咱们可使用 Chrome 的 API 或者是 JavaScript DOM API 都可以获得。数据结构
基于 Layout Tree,咱们就能够处理 overflow 等一系列复杂状况。但还有一个个问题是,这种数据结构没有将输入的计算属性和输出的视图位置分离开,因此这里说起了一个正在开发的新项目名为 LayoutNG 就是为了解决这个问题。架构
咱们假设初次渲染已经完成,可是,对于前端的快速发展,大量的逻辑已经由后端转往前端实现,DOM 的更新变得异常频繁。简单地说,咱们须要在原有 DOM 上作适量的改动从新渲染。为了避免从新将上图的整个流程所有再次进行,这里咱们就须要将其中的某些状态保留,提升更新效率。异步
在更新渲染时,有时咱们会缩放页面,区域滚动,或者是有动画。在这类型的状况下,若是渲染速率低于60帧,那么人眼看到会变得有些卡顿。布局
因此咱们要尽量判断出在上节提到的每个步骤中,有哪些元素是须要改变的,哪些不须要是能够从新利用的,作到效率的优化。这也是在技术实现中也被考虑到的地方。
可是,实际状况是,有时一个大的区域所有改变,那么咱们不得不对这个大的区域进行所有从新渲染,好比区域滚动。
还要注意的是 JavaScript 的设计是单线程的,也就意味着在渲染时,加入有 JS 脚本的执行,就会阻塞当前的渲染。
基于以前提到的种种问题,Chromium 团队提出了 compositing 这种解决方案。目的就是优化性能。有点相似于 Photoshop,简单得说,有两点:
在咱们进行动画,滚动,缩放等操做时,浏览器会监听用户的输入行为,在 impl 线程上进行工做,使得主线程执行 JavaScript,互不干扰,可是假如 impl 线程发现这个事件没法处理,则仍是会交还给主线程。
在实现层这个概念时仍是会借鉴初次渲染的数据结构,也就是树,称为 Layer Tree。它是命名在 cc(Chromium compositor)下,主要数据信息由以前的 Layout Tree 继承而来。注意,这里还有一个 PaintLayer Tree, 相似于一个中间状态,将一个 Layout Object 进行分层,而且赋予其功能,例如对子元素进行裁切或者是施加别的效果。
天然而然,咱们将会在 layout 和 paint 这两个阶段中加入 compositing update 去加快大区域从新渲染,得到 layer tree。须要注意的是,如今团队中正在进行一个工程,称为 slimming paint,将 layer tree 的创建放在 paint 阶段后,目的是为了将每一层 layer 的创建变得更加独立,而且创建属性树,提取出独立或者公共的属性,尽量地将其放到真正像素级渲染以前。当 impl 线程的 paint 阶段结束后,就能够通知主线程进行同步,有点相似于使用 git 在不一样分支上合并代码。
在 raster 以前还有一步优化,对于大面积滚动视图,没有必要一开始将全部的内容所有变换成 bitmaps,咱们只须要将视窗中的先进行转化,在这里有一个 tiling manager,它负责将区域分块,就像地板上的瓦块同样,随着滚动区域的变化,将相邻区域的瓦块优先渲染。
全部主要的阶段已经大致介绍完毕。欢迎补充和加深!
感谢张冀韬同窗将演讲内容梳理成文章并于掘金首发。