[译]深入了解现代web浏览器(三)
本文是根据Mariko Kosaka在谷歌开发者网站上的系列文章https://developer.chrome.com/blog/inside-browser-part3/ 翻译而来,共有四篇,该篇是第三篇。对于其中一些直译出来不太好理解的句子,笔者做了加工处理和提炼。
渲染器进程的内部工作
在前面我们介绍了多进程架构和导航流程,在这篇文章中我们将看看渲染器进程内部发生了什么。
渲染器进程涉及到web性能的许多方面。渲染器进程内部运行的细节非常之多,而本篇文章只是做一个概览;如果你想要深入了解,在这里可以找到更多资源。
渲染器进程处理web内容
渲染器进程负责响应tab页面中发生的所有事情。在渲染器进程中,绝大部分代码都是由主线程处理;如果你使用了web worker或是service worker,则你的Javascript代码是由工作者线程(worker thread)来处理。合成器和光栅化线程也是运行在渲染器进程中的——以此让页面更加高效、流程地渲染。
渲染器进程的核心工作就是将HTML,CSS和Javascript转换为能够让用户交互的web页面。

渲染器进程内部包括了主线程、工作者线程、合成器线程和光栅化线程
解析
DOM的构建
当渲染器进程接收到导航的提交消息并开始接收HTML数据时,主线程开始解析文本字符串(HTML)并将其转换为文档对象模型(DOM)。
DOM是浏览器对页面的内部表示,也是web开发人员可以通过JavaScript与之交互的数据结构和API。
将HTML文档解析为DOM由HTML标准定义。您可能已经注意到,将HTML提供给浏览器解析永远不会引发错误。例如,缺少
Hi!I'm Chrome!(b标签在i标签之前关闭)这样的错误标记会被视为Hi!I'm Chrome!。这是因为HTML规范被设计为是可以优雅地处理这些错误的。如果您对这些事情是如何完成的感到好奇,您可以阅读HTML规范的解析器中的错误处理和奇怪案例简介部分。
子资源加载
一个网页通常还会引用外部资源像图片,CSS和Javascript。这些文件需要从网络或者缓存中加载。主线程会在解析构建DOM的过程中找到它们并一一请求。但为了加快这一过程,会同时运行一个“预加载扫描器”;如果HTML文档中有类似于或这样的标签,预加载扫描器会在HTML解析器生成对应的token时找到它并向浏览器进程中的网络线程发送请求,因此这些子资源的加载不会影响到DOM树的解析构建(下面会讲到Javascript资在大多数情况下是会影响到DOM解析构建的)。

主线程解析HTML并构建DOM树
Javascript会阻塞解析
当HTML解析器遇到一个标签时,它就不得不停止对HTML文档的解析,转而去加载、解析和执行Javascript代码。为什么呢?因为Javascript可以只用诸如document.write()的代码来改变整个DOM的结构(HTML标准中的overview of the parsing model小节处的示意图很好地描述了这一过程)。这就是为什么HTML解析器不得不等待Javascript运行完后才能继续解析HTML文档。如果你对Javascript执行中发生的事情感兴趣,可以阅读V8团队的JavaScript engine fundamentals
提示浏览器如何加载资源
web开发人员有多种方式来给浏览器提示,以便更好地加载资源。如果你的Javascript代码中没有使用诸如document.write()这样会改变DOM结构的API,可以添加async或者defer属性到