Google chrome 为什么第一次上漆要在上漆之前进行

Google chrome 为什么第一次上漆要在上漆之前进行,google-chrome,google-chrome-devtools,domcontentloaded,Google Chrome,Google Chrome Devtools,Domcontentloaded,我正在潜入谷歌Chrome附带的性能工具中,试图了解性能改进技术。我正在玩Timeline选项卡,我发现在我的页面上,第一个Paint事件发生在DOMContentLoaded事件之前。我读了几篇文章,据说浏览器开始向用户显示内容的第一刻必须在DOMContentLoaded之后。谁能解释一下这是真的吗?好问题!据我所知,情况并非总是如此。浏览器需要绘制的是渲染树,这意味着它需要DOM和CSSOM,但关键是存在一些障碍,如解析器阻止Java脚本或渲染阻止CSS,它们可以停止此过程。但是您的问题是

我正在潜入谷歌Chrome附带的性能工具中,试图了解性能改进技术。我正在玩Timeline选项卡,我发现在我的页面上,第一个Paint事件发生在DOMContentLoaded事件之前。我读了几篇文章,据说浏览器开始向用户显示内容的第一刻必须在DOMContentLoaded之后。谁能解释一下这是真的吗?

好问题!据我所知,情况并非总是如此。浏览器需要绘制的是渲染树,这意味着它需要DOM和CSSOM,但关键是存在一些障碍,如解析器阻止Java脚本或渲染阻止CSS,它们可以停止此过程。但是您的问题是关于DOMContentLoaded的,如果您阅读了在中为user agent定义的步骤,特别是步骤4中,您将看到每当没有脚本可供执行时就会触发此事件,但是如果您通过这样做将脚本标记为“延迟”或“异步”,那么您将保证脚本不会在CSSOM上查询。下面是我从虚拟示例注释中捕获的时间线,我将java脚本标记为defer:在这个图表中,您可以看到第一个绘制在DCL之前!
这也是一篇关于分析Ilya Grigorik编写的关键渲染路径的好文章,DOMContentLoaded意味着解析器已完成将HTML转换为DOM节点并执行任何同步脚本

这并不妨碍浏览器呈现不完整的DOM/CSSOM树。事实上,它必须能够在javascript查询CSS属性时执行回流。如果它可以在不完整的树上进行回流,那么它也可以渲染它们

这也适用于从服务器流式传输的大型文档。用户可以在完成加载之前开始读取它

重要的是要理解,整个解析/评估/呈现过程是一个流处理管道,其中一些部分甚至并行/推测地完成。管道的后期阶段不会等待早期阶段完成,而是在它们到达时获取输出,并在有足够的信息可用于执行下一个增量时对其进行处理

例如,解析器显然不能在处理其所有属性之前发出元素节点,但它可以在处理其子树的同时发出节点。渲染器可以渲染没有子节点的节点。并且,它可能只是在稍后进行回流时才使用不完整的样式进行渲染,例如,当javascript插入另一个样式表时,或者仅仅因为尚未插入的子节点影响其渲染方式

重要的是要理解这是一个渐进的过程。对于 更好的用户体验,渲染引擎将尝试显示 尽快在屏幕上显示内容。它不会等到一切结束 HTML在开始构建和布局渲染树之前被解析。 部分内容将被解析和显示,而进程 继续处理来自 网络


当html中有
时,第一次绘制将发生在加载DOMContentLoaded之前。如MDN中所述

带有defer属性的脚本将阻止触发DOMContentLoaded事件,直到脚本加载并完成计算

并且带有defer属性的脚本不会阻止解析和绘制。 下面的图片显示了我在chrome中测试html页面时使用和不使用
的结果

带有

没有

请原谅我的错误,“关键资源是可能会阻止页面初始呈现的资源”据我所知,CSSOM是关键资源,在首次呈现之前需要完整的CSSOM。我错了吗?@Al-Alamin如果我正确阅读了规范,那么样式表只能是脚本阻塞(并且只有在某些条件下)。一些脚本反过来可能被解析器阻塞。只有当脚本阻止样式表出现在
中解析器阻止脚本之前时,样式表块才能有效阻止初始绘制,否则可能会发生局部绘制。如果它们位于
或插入的脚本中,则无论如何都可以进行部分渲染。