Why First Paint is happening before DOMContentLoaded
Asked Answered
P

3

21

I'm diving into performance tools that are shipped with Google Chrome as I'm trying to get my head around performance improvements techniques. I'm playing around with Timeline tab, and I found that on my page First Paint event is happening before DOMContentLoaded event. I read a few articles and reportedly the first moment when browser can start displaying stuff to the user must be after DOMContentLoaded. Could somebody please explain it this is true?

Prairie answered 15/12, 2015 at 12:38 Comment(0)
D
14

DOMContentLoaded means that the parser has completed converting the HTML into DOM nodes and executed any synchronous scripts.

That does not preclude the browser from rendering an incomplete DOM/CSSOM tree. In fact it has to be able to perform reflows anyway in case javascript queries computed CSS properties. And if it can do reflows on incomplete trees it may as well render them.

This is also relevant for large documents streamed from a server. The user can already start reading it before it has completed loading.

It is important to understand that the whole parsing / evaluation / rendering process is a stream processing pipeline with some parts even done in parallel / speculatively. The later stages of the pipeline do not wait for the earlier stages to finish, instead they take the outputs as they arrive and process them as soon as enough information is available to do the next increment.

E.g. the parser obviously cannot emit Element nodes before processing all of its attributes, but it can emit the node while still processing its child tree. And the renderer may render the node without its children. And it may be rendered with incomplete styles only to undergo a reflow later, e.g. when javascript inserts another style sheet or simply because the child nodes which have yet to be inserted affect how it will be rendered.

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.

Historically (at least in firefox) there used to be an initial paint delay during which the page was not rendered until it either was ready or the delay timer expired. The default setting for that delay was lowered repeatedly over the years until it reached 5ms which is less than the refresh rate interval on many monitors (16ms on 60Hz displays). This behavior may have lead to the inaccurate impression that pages are only rendered on DOMContentLoaded, but even back then a user would still have seen a partial page render on a sufficiently slow page.

Depreciation answered 19/12, 2015 at 8:7 Comment(2)
Forgive me if I am wrong, "A critical resource is a resource that could block initial rendering of the page" So far as I understood, CSSOM was critical resource and complete CSSOM was required before first rendering. was I wrong?Yemen
@Yemen if I read the specs correctly then stylesheets can only be script-blocking (and only under some conditions). Some scripts in turn can be parser-blocking. Only when a script-blocking stylesheet is present before a parser-blocking script in the <head> can a stylesheet block effectively block an initial paint, otherwise partial paints may happen. And if they're located in the <body> or script-inserted then a partial render is possible anyway.Depreciation
P
1

First paint will happen before DOMContentLoaded when there is <script defer> in html. As explained in MDN

Scripts with the defer attribute will prevent the DOMContentLoaded event from firing until the script has loaded and finished evaluating.

And scripts with the defer attribute will not prevent parsing and painting. The following pictures show the results I have test the html page with and without <script defer> in chrome

Html page with <script defer> enter image description here

Html page without <script defer> enter image description here

Personify answered 7/8, 2020 at 10:49 Comment(1)
I think you are mixing up two different things. DOMContentLoaded fires if the dom tree has been rendered and parsed. As JS can modify the DOM, the dom tree will wait for JS to be loaded, unless its loaded async/defer. The FP may happen before DCL as stated in the selected answer. So using async for your JS caused that your DCL went faster, but that it happened before FP was luck, they are not related. See also #2415250Litton
I
-1

Great question! as I know this is not always the case. What browser needs to paint is the render tree and that means it needs DOM and CSSOM but the point is that there are obstacles like parser blocking Java Script or render blocking CSS which can stop this process. But your question is specifically about DOMContentLoaded if you read the steps defined for user agent in 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 in this chart you can see that first paint is before DCL! This is also a good article about analyzing critical rendering path written by Ilya Grigorik

Isomerism answered 19/12, 2015 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.