解析器阻塞与渲染阻塞

25

我一直在阅读谷歌开发者文档,了解如何优化网页性能。但是,我对其中使用的术语有点困惑。CSS 和 JavaScript 文件都会阻塞 DOM 构建。但是,CSS 被称为“渲染阻塞”,而 JavaScript 被称为“解析器阻塞”。那么,“解析器阻塞”和“渲染阻塞”的术语有什么区别吗?还是它们指的是同样的事情,只是用词上有所不同?


从文档中可以了解到,JavaScript 也可以阻止 DOM 构建并延迟页面的渲染(即“解析器阻塞”)。而 CSS 则被视为渲染阻塞资源,这意味着浏览器会暂停任何已处理内容的渲染,直到 CSSOM 构建完成(即“渲染阻塞”)。 - Rayon
3个回答

42
假设一个HTML页面有两个 <script src="..."> 元素。解析器看到第一个元素后,必须停止*解析,同时获取并执行javascript,因为它可能包含 document.write() 方法调用,这会根本改变随后的标记解析方式。与浏览器执行的其他任务相比,通过互联网获取资源要慢得多,因此,解析器无事可做,只能等待。最终JS到达,执行完成后,解析器才能继续。然后它看到第二个 <script src="..."> 标签,并且必须再次等待资源加载完成。这是一个按顺序进行的过程,这就是解析器阻塞。
CSS资源是不同的。当解析器看到要加载的样式表时,它发送请求到服务器然后继续执行。如果还有其他资源需要加载,则可以并行获取所有这些资源(受某些HTTP限制)。但是只有当CSS资源已经加载并准备好后,页面才能呈现在屏幕上。这就是渲染阻塞,由于获取是并行的,所以减速的情况较不严重。
* 在一些现代浏览器中,解析器阻塞不像那么简单。它们有一些先进的功能,可以试图解析随后的HTML,希望当脚本加载和执行时,它不会对后续的解析产生影响;或者如果它确实有影响,那么仍需要加载相同的资源。但是如果脚本做了一些棘手的事情,它们仍然可能不得不回溯到工作。

1
感谢您的精彩解释。这确实帮助我理解了! - M00
还有一种被称为“预加载扫描”的技术,浏览器会提前查看并请求获取多个JS/CSS文件。然而,浏览器可以发起的并行调用数量是有限制的。 - ankit_m
由于@ankit_m提到的原因,即使脚本不依赖于DOM,有时将async添加到HTML页面上的最后一个脚本也是有意义的。这样浏览器就可以预加载甚至执行脚本,优化关键渲染路径。 - Novice
1
如果CSS是渲染阻塞的,那么为什么我们会看到FOUC(未样式化内容的闪烁)? - darKnight
一些解释在这里:https://dev59.com/ga_la4cB1Zd3GeqPwrH7 - Jithin Nair

4

CSS的渲染阻塞不会阻止DOM的构建,它只会阻止内容显示/渲染直到CSSOM准备就绪。但有一个特殊情况需要注意:

如果在外部CSS的<link>标签下有任何内联的<script>,即使那只是一个不包含任何JavaScript的空的<script>标签,HTML中在该<script>标签下方的DOM构建仍然会被阻止直到外部的CSS被获取。如果你的网络连接较慢,那个空的<script> 仍然会导致DOM构建的长时间延迟。因为<script>标签等待外部CSS,而DOM构建则等待这个脚本。在这种情况下,外部CSS资源隐式地导致解析阻塞。


0
还有一件事需要记住。在CSS加载之前,您可以通过内联样式在屏幕上实现FP(First Paint)。怎么做? 只需在要先显示的元素后添加对CSS的引用即可。 例如:
<html>
<body>
<h1 style="color:red"> I will be displayed on the screen and I will be RED</h1>
<link rel="stylesheet" href="styles.css">
<h2> Every elementfrom this point forward (including me) will wait for the CSS to load first and then be displayed on the screen</h2>
</body>
</html>

注意:我应该提到我在这里所做的被视为不良实践。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接