为什么 First Paint 在 DOMContentLoaded 之前发生
Why First Paint is happening before DOMContentLoaded
我正在研究 Google Chrome 附带的性能工具,因为我正试图了解性能改进技术。我正在玩时间轴选项卡,我发现在我的页面上 First Paint 事件发生在 DOMContentLoaded 事件之前。我读了几篇文章,据说浏览器可以开始向用户显示内容的第一时间必须在 DOMContentLoaded 之后。有人可以解释一下这是真的吗?
好问题!据我所知,情况并非总是如此。浏览器需要绘制的是渲染树,这意味着它需要 DOM 和 CSSOM 但关键是存在解析器阻塞 Java 脚本或渲染阻塞 CSS 可以停止这个过程。但是您的问题具体是关于 DOMContentLoaded 如果您阅读此图表中 http://www.w3.org/TR/html5/syntax.html#the-end and specially step 4 you will see the this event is fired whenever there is no script left for execution but what if you mark the script with defer or async by doing this you promise that the script will not query on CSSOM. Here is the time line I captured from my dummy sample note that I marked java script as defer: TimeLine Example 中为用户代理定义的步骤,您会看到第一次绘制是在 DCL 之前!
这也是 Ilya Grigorik 写的一篇关于分析关键渲染路径的好文章
DOMContentLoaded 表示解析器已完成将 HTML 转换为 DOM 节点并执行任何同步脚本。
这并不排除浏览器呈现不完整的 DOM/CSSOM 树。事实上,它必须能够在 javascript 查询计算 CSS 属性的情况下无论如何执行回流。如果它可以对不完整的树进行回流,它也可以渲染它们。
这也适用于从服务器流式传输的大型文档。在加载完成之前用户已经可以开始阅读了。
重要的是要了解整个解析/评估/渲染过程是一个流处理管道,其中一些部分甚至是并行/推测性完成的。管道的后期阶段不会等待早期阶段完成,而是在输出到达时获取输出,并在有足够的信息可用以执行下一个增量时立即处理它们。
例如解析器显然不能在处理其所有属性之前发出 Element 节点,但它可以在仍在处理其子树的同时发出节点。渲染器可能会渲染没有其子节点的节点。它可能会以不完整的样式呈现,只是为了稍后进行回流,例如当 javascript 插入另一种样式时 sheet 或仅仅因为尚未插入的子节点会影响它的呈现方式。
http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/#The_main_flow
It's important to understand that this is a gradual process. For
better user experience, the rendering engine will try to display
contents on the screen as soon as possible. It will not wait until all
HTML is parsed before starting to build and layout the render tree.
Parts of the content will be parsed and displayed, while the process
continues with the rest of the contents that keeps coming from the
network.
历史上(至少在 firefox 中)曾经有一个初始绘制延迟,在此期间页面不会呈现,直到它准备好或延迟计时器过期。该延迟的默认设置 was lowered repeatedly over the years 直到达到 5 毫秒,这小于许多显示器的刷新率间隔(60Hz 显示器上为 16 毫秒)。
这种行为可能导致页面仅在 DOMContentLoaded
上呈现的错误印象,但即使在那时,用户仍然会看到部分页面在足够慢的页面上呈现。
当 html 中有 <script defer>
时,第一次绘制将在 DOMContentLoaded 之前发生。如 MDN
中所述
具有 defer 属性的脚本将阻止触发 DOMContentLoaded 事件,直到脚本加载并完成评估。
并且带有defer属性的脚本不会阻止解析和绘制。
下面的图片显示了我在 chrome
中使用和不使用 <script defer>
测试 html 页面的结果
Html 页面 <script defer>
Html 页面没有 <script defer>
我正在研究 Google Chrome 附带的性能工具,因为我正试图了解性能改进技术。我正在玩时间轴选项卡,我发现在我的页面上 First Paint 事件发生在 DOMContentLoaded 事件之前。我读了几篇文章,据说浏览器可以开始向用户显示内容的第一时间必须在 DOMContentLoaded 之后。有人可以解释一下这是真的吗?
好问题!据我所知,情况并非总是如此。浏览器需要绘制的是渲染树,这意味着它需要 DOM 和 CSSOM 但关键是存在解析器阻塞 Java 脚本或渲染阻塞 CSS 可以停止这个过程。但是您的问题具体是关于 DOMContentLoaded 如果您阅读此图表中 http://www.w3.org/TR/html5/syntax.html#the-end and specially step 4 you will see the this event is fired whenever there is no script left for execution but what if you mark the script with defer or async by doing this you promise that the script will not query on CSSOM. Here is the time line I captured from my dummy sample note that I marked java script as defer: TimeLine Example 中为用户代理定义的步骤,您会看到第一次绘制是在 DCL 之前! 这也是 Ilya Grigorik 写的一篇关于分析关键渲染路径的好文章
DOMContentLoaded 表示解析器已完成将 HTML 转换为 DOM 节点并执行任何同步脚本。
这并不排除浏览器呈现不完整的 DOM/CSSOM 树。事实上,它必须能够在 javascript 查询计算 CSS 属性的情况下无论如何执行回流。如果它可以对不完整的树进行回流,它也可以渲染它们。
这也适用于从服务器流式传输的大型文档。在加载完成之前用户已经可以开始阅读了。
重要的是要了解整个解析/评估/渲染过程是一个流处理管道,其中一些部分甚至是并行/推测性完成的。管道的后期阶段不会等待早期阶段完成,而是在输出到达时获取输出,并在有足够的信息可用以执行下一个增量时立即处理它们。
例如解析器显然不能在处理其所有属性之前发出 Element 节点,但它可以在仍在处理其子树的同时发出节点。渲染器可能会渲染没有其子节点的节点。它可能会以不完整的样式呈现,只是为了稍后进行回流,例如当 javascript 插入另一种样式时 sheet 或仅仅因为尚未插入的子节点会影响它的呈现方式。
http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/#The_main_flow
It's important to understand that this is a gradual process. For better user experience, the rendering engine will try to display contents on the screen as soon as possible. It will not wait until all HTML is parsed before starting to build and layout the render tree. Parts of the content will be parsed and displayed, while the process continues with the rest of the contents that keeps coming from the network.
历史上(至少在 firefox 中)曾经有一个初始绘制延迟,在此期间页面不会呈现,直到它准备好或延迟计时器过期。该延迟的默认设置 was lowered repeatedly over the years 直到达到 5 毫秒,这小于许多显示器的刷新率间隔(60Hz 显示器上为 16 毫秒)。
这种行为可能导致页面仅在 DOMContentLoaded
上呈现的错误印象,但即使在那时,用户仍然会看到部分页面在足够慢的页面上呈现。
当 html 中有 <script defer>
时,第一次绘制将在 DOMContentLoaded 之前发生。如 MDN
具有 defer 属性的脚本将阻止触发 DOMContentLoaded 事件,直到脚本加载并完成评估。
并且带有defer属性的脚本不会阻止解析和绘制。 下面的图片显示了我在 chrome
中使用和不使用<script defer>
测试 html 页面的结果
Html 页面 <script defer>
Html 页面没有 <script defer>