Is JavaScript Execution Deferred Until CSSom Is Built or Not

Is JavaScript execution deferred until CSSOM is built or not?

This quote is true, but it means that if you place your style sheet first, and a script after it, the script will not execute until the style sheet is downloaded and parsed. See this example:

test.php:

<?php
sleep(5);
header('Content-Type: text/css');
echo 'body {background-color: red;}';

index.html:

<link rel="stylesheet" href="test.php">
<script>console.log('done');</script>

The console.log call won't be executed until background color changes to red.

This leads to the conclusion that building CSSOM isn't done once for all style sheets, but it's a gradual process – when browser encounters a style sheet, it downloads it, parses, and moves next. Also probably browser first makes a list of all CSS resources and adds them to the download queue, even before executing any scripts. That would explain why the request is made even though the link tag is commented by a script.

How does browser loads DOM and CSSOM partially?

CSSOM stops parsing. Thus execution of subsequent script tags, and also delays rendering.

Script tags before style tags will execute before CSS is loaded into CSSOM from style tags afterwards.

Style tags that come after script tags will alter CSSOM. And if script accessed styles that are being altered then what it read is outdated. Order matters.

Parsing is stopped not just rendering.

JavaScript blocks parsing because it can modify the document. CSS
can’t modify the document, so it seems like there is no reason for it
to block parsing, right?

However, what if a script asks for style information that hasn’t been
parsed yet? The browser doesn’t know what the script is about to
execute—it may ask for something like the DOM node’s background-color
which depends on the style sheet, or it may expect to access the CSSOM
directly.

Because of this, CSS may block parsing depending on the order of
external style sheets and scripts in the document. If there are
external style sheets placed before scripts in the document, the
construction of DOM and CSSOM objects can interfere with each other.
When the parser gets to a script tag, DOM construction cannot proceed
until the JavaScript finishes executing, and the JavaScript cannot be
executed until the CSS is downloaded, parsed, and the CSSOM is
available

.

https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/

When and how do browsers render style tag in body?

TL;DR:

In short, the answer to your question is: once a <style> tag is met inside <body> everything stops and the CSSOM is being rebuilt and re-applied to all existing rendered (painted) content.

Placing <style> tags inside <body> is considered bad practice because it can create FOUC. But if your <style> tag only contains rules for elements placed after it in DOM, placing it in body is perfectly fine, as no FOUC can happen.


The render process of a page is quite complex. But, overly-simplified, here's what happens

  1. <head> is read and CSSOM is built. All CSS is render blocking, unless explicitly specified otherwise by use of @media queries. The non-blocking CSS is still loaded, it's not entirely skipped.
  2. DOM building and CSSOM building are ran in paralel, but all <script> execution is deferred until CSSOM has been built (on </head> tag met), at which point all loaded <script>s are ran, blocking DOM building. JS can make changes to CSSOM at this point. *
  3. Placing <style> tags inside <body> interrupts everything (JS execution and DOM building), CSSOM is being updated and applied to the already rendered content, if any. Everything is resumed after.

* On further testing it appears <head> parsing is single threaded. CSSOM building does block javascript execution but it's done is stages, as each <link /> and <style> tags are met (a <script> placed after a <link> will only execute after the <link /> was resolved and applied to CSSOM). <script> tags placed in between CSS resources are not deferred until all CSS resources in <head> are parsed, as I initially thought.

And, of course js can make changes to CSSOM at run time. See this question I asked for more on how js execution is blocked by CSSOM building.


All the above apply to the normal loading, without considering async, which adds a whole new layer of complexity to it.

If you're interested in more details, I recommend going through the Performance chapter of Web Fundamentals, provided by Google.

does CSSOM and DOM construction happens on parallel threads?

In order to render the page the browser has to do multiple complex steps, in generality these steps are : parsing/loading, style calculation, creating layout tree, paint, and then finally Rasterisation ( in this step the browser takes the results that was generated from all the previous steps, and turn that info into colored pixels that are drawn on your screen).

In short, in the parsing/loading step, the main thread starts parsing the html, and creating the dom tree, and when it reach - or even peak about - external resources it starts loading these resources in a background network thread(s). unless you defer loading these resources, the browser still needs to parse/execute them before going to next step.

In the style calculation step, the browser determines styles for each node, this also happens in the main thread, and needs to happen after dom has been created. styles can not be calculated in parallel with dom parsing, because styles need to be calculated based on css selectors, and css selectors are meaningless without the dom tree being completely structured and ready to be read - up till the point where that style declaration appears.

After styles are calculated, browsers start creating layout tree - you could think of the layout tree as a huge rectangular grid created of smaller rectangles, where the browser knows where every element is positioned and in which small rectangle in the whole grid, along with x,y coordinates, and bounding boxes size. This step also happens in the main thread, and can not be parallel with style calculation, because it needs dom and cssom as inputs in order to produce its output.

After that painting comes, also happens in main thread, and again needs the previous results as its input, and so can not be parallel with layout creation, in this step the browser creates painting structures for the whole layout tree.

From here the browser commit all this information to the Compositor thread, this is where things in parallel start to happen, the compositor thread knows how to take the layout tree, and composite that into frames that you see. The compositor thread is extremely smart, it knows how to prioritise and parallelize workload, it sends its workload to different rasterisation threads, and these are responsible for giving you the colored pixels that are drawn in your screen.

The Compositor thread is not only used for the initial render, but also used anytime the main thread wants to render stuff. In fact when you are scrolling, you are scrolling on the compositor thread, and recently chromium has been moving a lot of stuff to the compositor thread, so that even if the main thread gets blocked then ui still behaves smoothly. If you want to learn more about the compositor thread you can also see this link (along with the one i previously shared)



Related Topics



Leave a reply



Submit