我总是看到一个网页的渲染流程,如下图所示:
因此,绘画只在解析DOM树并创建CSSOM后才开始,对吧?另一种说法是,最后的
做法是最佳实践,以便在下载脚本之前页面呈现内容.
我的问题是,什么时候解析DOM树,我们怎么说它已经完成了?在我的理解中,最终也是DOM树的一部分,只有加载了脚本才能调用DOM树创建.浏览器从上到下读取html文件,创建DOM树,当它看到时
,它停止下载并执行它,直到解析遍历整个页面.或者,页面是否在解析DOM树的同时绘制页面?
TL; DR:收到文档后,解析即刻开始.
有关更详细的说明,我们需要深入了解渲染引擎的工作方式.
渲染引擎解析HTML文档并创建两个树:the content tree
和the render tree
.内容树包含所有DOM节点.渲染树包含所有样式信息(CSSOM
),只包含渲染页面所需的DOM节点.
一旦创建了渲染树,浏览器就会经历两个过程:应用layout
和painting
每个DOM节点.应用布局意味着计算DOM节点应出现在屏幕上的精确坐标.绘画意味着实际渲染像素并应用风格属性.
这是一个渐进的过程:浏览器不会等到所有HTML都被解析.将解析和显示部分内容,同时继续处理来自网络的其余内容.
您可以在浏览器中看到此过程.例如,打开Chrome开发者工具并加载您选择的网站.
在Network
选项卡中记录活动后,您会注意到在下载文档时开始解析.它识别资源并开始下载它们.蓝色垂直线表示DOMContentLoaded
事件,红色垂直线表示load
事件.
记录时间表可以让您更深入地了解幕后发生的事情.我已将上面的屏幕截图作为示例包含,以指示在解析文档时发生绘画.请注意,初始绘制就在它继续解析文档的另一部分之前发生.此过程一直持续到文档结束.
渲染引擎是单线程的.除了网络操作之外,几乎所有事情都发生在这个线程中.
将其与网络的同步性结合起来.开发人员希望立即解析并执行(即:解析器一旦到达脚本标记).这意味着:
必须从网络获取资源(由于DNS查找和连接速度,这可能是一个缓慢的过程).
资源的内容将传递给Javascript解释器.
解释器解析并执行代码.
解析文档会暂停,直到此过程结束.您不会通过在文档末尾包含's来改善总解析时间.它确实增强了用户体验,因为解析和绘制过程不会被
需要执行的过程中断.
通过使用defer
和/或标记资源可以解决此问题async
.async
在HTML解析期间下载文件,并在完成下载后暂停HTML解析器执行它.defer
在HTML解析期间下载文件,并且只在解析器完成后才执行它.
一些浏览器旨在通过使用所谓的推测解析来解决阻塞问题.在下载和执行脚本时,引擎会向前解析(并运行HTML树构造!).Firefox和Chrome使用这种技术.
如果推测成功,您可以想象性能提升(例如,DOM没有被文档中包含的脚本改变).等待脚本执行不是必需的,页面已成功绘制.不利的一面是,当投机失败时,会有更多的工作损失.
对我们来说幸运的是,非常聪明的人会使用这些技术,所以即使document.write
正确使用也不会破坏这个过程.另一个经验法则是不使用document.write
.例如,它可以破坏推测树:
// Results in an unbalanced tree // Results in an unfinished token
以下资源值得您花时间阅读:
Web Fundamentals(Google Developers)
浏览器如何工作
关于HTML5 Parser的 MDN
浏览器渲染(视频)简介