深入了解现代网络浏览器(第 3 部分)

渲染器进程的内部工作

在这篇文章中,我们将看看渲染器进程内部发生了什么。

渲染器过程涉及 Web 性能的许多方面。由于渲染器进程内部发生了很多事情,这篇文章只是一个概述。如果您想深入挖掘, Web Fundamentals 的性能部分 有更多资源。

渲染器进程处理 Web 内容

渲染器进程负责选项卡内发生的所有事情。在渲染器进程中,主线程处理您发送给用户的大部分代码。如果您使用 Web Worker 或 Service Worker,有时您的 JavaScript 的某些部分由工作线程处理。合成器和光栅线程也在渲染器进程内部运行,以高效、流畅地渲染页面。

渲染器进程的核心工作是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页。

image

解析

DOM的构建

当渲染器进程接收到导航的提交消息并开始接收 HTML 数据时,主线程开始解析文本字符串 (HTML) 并将其转换为文档对象模型 ( DOM )。

DOM 是浏览器对页面的内部表示,也是 Web 开发人员可以通过 JavaScript 与之交互的数据结构和 API。

将 HTML 文档解析为 DOM 由 HTML 标准定义。您可能已经注意到,将 HTML 提供给浏览器永远不会引发错误。例如,缺少结束</p>标记是一个有效的 HTML。像(b 标签在 i 标签之前关闭)这样的错误标记Hi! <b>I'm <i>Chrome</b>!</i>被视为您编写了 Hi! <b>I'm <i>Chrome</i></b><i>!</i>. 这是因为 HTML 规范旨在优雅地处理这些错误。如果您对这些事情是如何完成的感到好奇,您可以阅读HTML 规范的“解析器中的错误处理和奇怪案例简介”部分。

资源加载

网站通常使用image、css 和 js 等外部资源。这些文件需要从网络或缓存中加载。主线程可以在解析构建DOM的过程中找到它们时一一请求,但为了加快速度,“预加载扫描器”是并发运行的。如果 HTML 文档中有类似的东西<img>,<link>预加载扫描器会查看 HTML 解析器生成的令牌,并向浏览器进程中的网络线程发送请求。

image

JavaScript 可以阻止解析

当 HTML 解析器找到一个<script>标签时,它会暂停 HTML 文档的解析,并且必须加载、解析和执行 JavaScript 代码。为什么?因为document.write()可以通过js改变整个 DOM 结构之类的东西来改变文档的形状(HTML 规范中解析模型的概述 有一个很好的图表)。这就是为什么 HTML 解析器必须等待 JavaScript 运行才能恢复对 HTML 文档的解析。如果您对 JavaScript 执行过程中发生的事情感到好奇,V8 团队有关于此的演讲和博客文章

浏览器如何加载资源

Web 开发人员可以通过多种方式向浏览器发送提示,以便更好地加载资源。如果您的 JavaScript 不使用document.write(),您可以添加asyncdefer属性到<script>标记。然后浏览器异步加载和运行 JavaScript 代码,并且不会阻止解析。如果合适的话,你也可以使用JavaScript 模块。<link rel="preload">是一种通知浏览器当前导航肯定需要该资源,并且您希望尽快下载。您可以在资源优先级 - 让浏览器为您提供帮助中阅读更多相关信息。

样式计算

拥有 DOM 不足以了解页面的外观,因为我们可以在 CSS 中设置页面元素的样式。主线程解析 CSS 并确定每个 DOM 节点的计算样式。这是关于基于 CSS 选择器将哪种样式应用于每个元素的信息。您可以在DevTools 查看此信息。

image

即使您不提供任何 CSS,每个 DOM 节点也有一个计算样式。<h1>tag 显示得比<h2>tag 大,并且为每个元素定义了边距。这是因为浏览器有一个默认样式表。如果你想知道 Chrome 的默认 CSS 是什么样的, 可以在这里查看源代码

布局

现在渲染器进程知道文档的结构和每个节点的样式,但这还不足以渲染页面。想象一下,您正试图通过电话向您的朋友描述一幅画。“有一个大红色圆圈和一个小蓝色方块”不足以让您的朋友知道这幅画的确切外观。

image

布局是寻找元素几何形状的过程。主线程遍历 DOM 和计算样式,并创建包含 xy 坐标和边界框大小等信息的布局树。布局树可能类似于 DOM 树的结构,但它只包含与页面上可见内容相关的信息。如果该元素是display: none,则该元素不是布局树的一部分(但是,visibility: hidden在布局树中)。类似地,像p::before{content:"Hi!"} 的伪类,即使它不在 DOM 中,它也会包含在布局树中。

image

确定页面的布局是一项具有挑战性的任务。即使是最简单的页面布局,比如从上到下的block,也必须考虑字体有多大以及在哪里换行,因为这些会影响段落的大小和形状;然后影响下一段需要的位置。

CSS 可以使元素浮动到一侧,掩盖溢出项,改变书写方向。可以想象,这个布局阶段任务艰巨。在 Chrome 中,整个工程师团队都在处理布局。如果你想了解他们的工作细节, BlinkOn 会议上的演讲被记录下来了,非常有趣。

绘制

拥有 DOM、样式和布局仍然不足以呈现页面。假设您正在尝试复制一幅画。您知道元素的大小、形状和位置,但您仍然必须判断绘制它们的顺序。

例如,z-index可能为某些元素设置,在这种情况下,按照 HTML 中编写的元素顺序绘制将导致不正确的呈现。

image
image

在此绘制步骤中,主线程遍历布局树以创建绘制记录。绘画记录是“先背景,后文字,后矩形”的绘画过程的记录。如果您使用 canvas绘制元素,那么您可能对这个过程很熟悉。

image

重绘成本很高

在渲染管道中要掌握的最重要的事情是,在每个步骤中,前一个操作的结果都用于创建新数据。例如,如果布局树发生变化,则需要为文档的受影响部分重新生成绘制顺序。

此处为语雀视频卡片,点击链接查看:trees.mp4

如果您正在为元素设置动画,浏览器必须在每一帧之间运行这些操作。我们的大多数显示器每秒刷新屏幕 60 次 (60 fps);当您在每一帧都在屏幕上移动物体时,动画对人眼来说会显得很流畅。但是,如果动画错过了中间的帧,那么页面将出现“jank”。

image

即使你的渲染操作跟得上屏幕刷新,但是这些计算也在主线程上运行,这意味着当你的应用程序运行 JavaScript 时它可能会被阻塞。

image

您可以将 JavaScript 操作分成小块,并使用 requestAnimationFrame(). 有关此主题的更多信息,请参阅 优化 JavaScript 执行 。您也可以在 Web Workers 中运行 JavaScript 以避免阻塞主线程。

image

合成

你将如何绘制页面?

此处为语雀视频卡片,点击链接查看:naive_rastering.mp4

光栅化过程的动画

既然浏览器知道了文档的结构、每个元素的样式、页面的几何形状以及绘制顺序,那么它是如何绘制页面的呢?将这些信息转换为屏幕上的像素称为光栅化。

处理这个问题比较简单的一种的方法是在视口内光栅化其中一部分。如果用户滚动页面,则移动光栅框架,并通过光栅来填充更多缺失的部分。这就是 Chrome 在首次发布时处理光栅化的方式。然而,现代浏览器运行一个更复杂的过程,称为合成。

什么是合成

合成是一种技术,可以将页面的各个部分分成图层,分别将它们光栅化,然后在称为合成器线程的单独线程中合成为页面。如果发生滚动,由于图层已经被光栅化,它所要做的就是合成一个新的帧。可以通过移动图层并合成新帧。

此处为语雀视频卡片,点击链接查看:composit.mp4

合成过程动画

分层

为了找出哪些元素在哪些层中,主线程遍历布局树来创建层树。

image

您可能很想为每个元素赋予图层,但是跨越过多图层进行合成可能会导致比每帧光栅化小部分页面操作更慢,因此测量应用程序的渲染性能至关重要。

主线程的光栅和合成

一旦创建了层树并确定了绘制顺序,主线程就会将该信息提交给合成器线程。合成器线程然后光栅化每一层。一个层可能会很大,因此合成器线程将它们分成小块并将每个小块发送到光栅线程。光栅线程光栅化每个图块并将它们存储在 GPU 内存中。

image

合成器线程可以优先考虑不同的光栅线程,以便可以先对视口内的事物进行光栅化。

完成光栅化后,合成器线程通过ipc将信息提交给浏览器进程。此时,可以从 UI 线程添加另一个合成器进程来更改浏览器 UI。这些合成帧被发送到 GPU 在屏幕上显示。如果出现滚动事件,合成器线程会创建另一个合成帧以发送到 GPU。

image

合成的好处是它是在不涉及主线程的情况下完成的。合成器线程不需要等待样式计算或 JavaScript 执行。这就是为什么 合成动画 被认为是流畅性能的最佳选择。如果需要再次计算布局或绘制,则必须涉及主线程。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容