浏览器如何部分加载 DOM 和 CSSOM?
Posted
技术标签:
【中文标题】浏览器如何部分加载 DOM 和 CSSOM?【英文标题】:How does browser loads DOM and CSSOM partially? 【发布时间】:2016-03-18 17:07:09 【问题描述】:首先让我简单概述一下它是如何加载的,然后我就问这个问题。
浏览器获取 HTML => 解析 html => 创建节点 => 解析节点并开始将它们转换为 Dom 元素 => 找到样式节点,然后开始创建 CSSOM => 在完成解析时,如果有样式标记,它会等待让它构造 CSSOM 树 => 一次两者都完成了,它合并了 DOM 和 CSSOM,并触发 DOMContentLoaded
事件。
总而言之,只要 CSSOM 准备就绪,浏览器就会开始渲染,并且可以逐步添加 Dom。
这一切都很好,但是当浏览器开始渲染页面而不是整个 html 加载时,流程是如何进行的..(例如在 nodejs 中,您可以部分 html 然后等待 2 秒然后发送更多)
-
如果页面底部有另一个样式标记怎么办。没有收到所有的 html,也没有 css 浏览器会开始渲染,但据我了解,渲染只发生在 cssom 完全构建之后。
脚本标签会发生什么,如果 css 未完成,则不会执行处理脚本标签,因此也会停止解析。 JS 在 CSSOM 完成后运行。
【问题讨论】:
渲染不必等待所有 CSS 可用。 developers.google.com/web/fundamentals/performance/… 根据这个 js,渲染发生在 cssom 完成后,cssom 阻塞一切的全部原因是 css 稍后可以更改输出,而稍后加载的 dom 元素不会改变输出,但只会添加到 dom 树中 据我了解:首先..解析和渲染是不同的阶段。 DOM 是增量构建的,这意味着无需加载整个 html 文件,只要字节从连接到达,它就会被解析。不是 CSS,首先获取整个 CSS 文件,然后进行解析。是的,CSS 链接/内联/嵌入会阻止解析。浏览器将等待 CSSOM 完成。在所有阻塞的 css/脚本都被获取执行/解析之后。只有在 DOMContentLoaded 被触发后,DOM/CSSOM 才被构建。现在开始造型和渲染。我在想他们只会阻止渲染,但不会阻止解析。 hacks.mozilla.org/2017/09/… 我的理解存在一些误区。构建完所有 CSSOM 后,JS 不会运行。只有 CSSOM 用于遇到的样式标签。脚本和样式标签按照声明的顺序执行(不使用延迟/异步)。 【参考方案1】:事情可能会阻止DOMContentLoaded
事件,但这不会阻止呈现不完整的页面。这对于从慢速服务器流式传输的非常长的页面可能很重要。
浏览器可以交错执行脚本、重新设置样式、渲染文档解析。这可以通过在 <head>
中执行 javascript 并查询 DOM 来简单地展示,您将看到在 DOMContentLoaded
事件触发之前,该文档将没有其所有节点(甚至可能没有正文元素)。
您必须将文档构建更多地视为一个流,而不是在下一个块开始之前运行到完成的顺序执行块。
【讨论】:
CCSOM构建后不是JS跑了吗? 没有。脚本、html 解析、css 解析所有相互交错,取决于它们在 html 中的位置(以及许多其他因素) 是的,我同意它们确实会相互影响,但是我想了解一些规则,谷歌关于 udacity 的这门课程说 js 是在 cssom 构建完成后运行的。 udacity.com/course/viewer#!/c-ud884/l-1469569174/m-1524418577 @the8472 该声明的来源是什么? Google specifically tells 浏览器延迟脚本执行和 DOM 构建直到它完成下载和构建 CSSOM @Veehmot 阅读问题的上下文。 “总而言之,只要 CSSOM 准备就绪,浏览器就会开始渲染,并且可以逐步添加 Dom。” 是非常错误的。仅仅因为您没有在DOMContentLoaded
的上下文中定义的完整 DOM 或 CSSOM,并不意味着没有可以呈现的内容,例如部分 CSS 状态。【参考方案2】:
CSSOM 停止解析。因此执行后续的脚本标签,也会延迟渲染。
样式标签之前的脚本标签将在 CSS 之后从样式标签加载到 CSSOM 之前执行。
脚本标签之后的样式标签会改变 CSSOM。如果脚本访问正在更改的样式,那么它读取的内容已经过时。订单很重要。
停止解析而不仅仅是渲染。
JavaScript 会阻止解析,因为它可以修改文档。 CSS 无法修改文档,所以似乎没有理由 阻止解析,对吧?
但是,如果脚本要求提供尚未提供的样式信息怎么办? 解析了吗?浏览器不知道脚本要做什么 执行——它可能会要求类似 DOM 节点的背景色 这取决于样式表,或者它可能期望访问 CSSOM 直接。
因此,CSS 可能会阻塞解析,具体取决于 文档中的外部样式表和脚本。如果有 放置在文档中脚本之前的外部样式表, DOM 和 CSSOM 对象的构造会相互干扰。 当解析器到达脚本标签时,DOM 构建无法继续 直到 JavaScript 完成执行,并且 JavaScript 不能被 执行直到 CSS 被下载、解析并且 CSSOM 被 可用
.
https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/
【讨论】:
如果停止解析,是不是也停止了渲染? 但这似乎不是真的。即使整个文档还没有被解析,渲染(对于已经解析的任何内容)也会发生。 是的,没错。但是我读过/误解了 JS 在页面上的所有 css 都被解析和应用后运行。在 CSSOM 之后运行 JS 是有冲突的,但答案都是正确的,但有一个区别; JS 在 CSSOM 完成后运行,但只有在它之前的 CSS,它不是所有的 css。【参考方案3】:几个重要的事实:
当文档已被 main 解析器完全解析并且 DOM 已完全构建时,将触发事件DOMContentLoaded
。
任何普通脚本(非异步或延迟)都会有效地阻止 DOM 构建。原因是脚本可能会改变 DOM。
引用样式表既不是解析器阻塞也不是 DOM 构造阻塞器。
如果在引用 CSS 后添加 <script>
(无论是外部的还是内联的),脚本的执行(不获取)会延迟到 CSS 的获取和解析完成即使脚本的提取更快完成。原因是脚本可能依赖于待加载的 CSS 规则。所以浏览器必须等待。
只有在这种情况下,CSS 才会间接地阻塞文档解析器和 DOM 构造。
当浏览器在脚本上被阻止时,第二个轻量级解析器会扫描标记的其余部分以寻找其他资源,例如样式表、脚本、图像等,也需要检索。这称为“预加载”。
【讨论】:
需要注意的是,即使样式是在脚本标签之前声明的,或者在脚本标签之前链接了一个大的css文件,domcontentloaded
事件可能会在css样式被解析之前触发。要解决这个问题,您需要在 js 代码的开头执行 forced css repaint。以上是关于浏览器如何部分加载 DOM 和 CSSOM?的主要内容,如果未能解决你的问题,请参考以下文章