Why does Chrome DevTools evaluate JavaScript before recalculating styles?

According to an article, CSS is considered render-blocking, so JavaScript will evaluate after constructing a CSSOM (also known as recalculating styles in dev tools).

However, it appears in Chrome dev tools that JavaScript is evaluated before CSSOM. Why is this the case? Did I misunderstand something? https://i.sstatic.net/xV8gD.png

If you'd like to view my example, click => here

Call Tree

https://i.sstatic.net/nt5k0.png

Event log https://i.sstatic.net/s36Ow.png

<html>
<head>
<style>
  h1 {color:red;}
  p>p {color:blue;}
  p>p>p {color:blue;}
  p>p>p>p {color:blue;}
  p>p>p>p>p {color:blue;}
  p>p>p>p>p>p {color:blue;}
  p>p>p>p>p>p>p {color:blue;}
  p>p>P>p>p>p>p>p {color:blue;}
</style>
</head>
<body>

<h1>A heading</h1>
<p>A paragraph.</p>
<p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline';  // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var loadTime = document.createElement('div');
      loadTime.textContent = 'You loaded this page on: ' + new Date();
      loadTime.style.color = 'blue';
      document.body.appendChild(loadTime);
      var cnt=0
      while(cnt++ <=9999999){} 
    </script>
</body>
</html>

Answer №1

The focus of the article is on the significance of the domContentLoaded event, which marks the moment when a page is ready to be displayed to the user, eliminating the dreaded white screen. The appearance of the blue vertical line in the timeline is crucial as it indicates how quickly the page becomes available. How long does the user have to endure the white screen before the content appears?

With the rise of single-page applications, much of the content is accessible only after the main scripts have loaded. This is why many top web applications opt for server-side rendered pages initially, before allowing JavaScript to take over for the single-page experience. Additionally, they utilize code-splitting to load only necessary components on each page.

The article delves into the impact of incorporating external CSS and JS files. The loading and parsing of these files can delay the domContentLoaded event, resulting in prolonged white screen transitions, even when the HTML content is ready to be displayed.

The performance event log provides insights into the process, showcasing events such as Event:readystatechange and Event:pageshow, which signify when the content is actually presented to the user. These events occur after script and style computations, with the <script> line potentially obstructing the domContentLoaded event until completion.

To prevent this issue, it is advisable to use the async attribute in the script tag to prevent blocking the white screen. Imagine if every external script on our webpage hindered page rendering - user frustration would be inevitable, potentially leading to abandonment.

We hope this explanation addresses your concerns.

Answer №2

Answer

One may notice certain optimizations when dealing with inline or parser blocking script in Chrome and IE11.

Upon testing the following HTML:

<html>
<head>
<style>
  h1 {color:red;}
  p>p {color:blue;}
  p>p>p {color:blue;}
  p>p>p>p {color:blue;}
  p>p>p>p>p {color:blue;}
  p>p>p>p>p>p {color:blue;}
  p>p>p>p>p>p>p {color:blue;}
  p>p>P>p>p>p>p>p {color:blue;}
</style>
</head>
<body>

<h1>A heading</h1>
<p>A paragraph.</p>
<p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline';  // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var loadTime = document.createElement('div');
      loadTime.textContent = 'You loaded this page on: ' + new Date();
      loadTime.style.color = 'blue';
      document.body.appendChild(loadTime);
      var cnt=0
      while(cnt++ <=9999999){} 
    </script>
</body>
</html>

IE11 displays the expected sequence but executes in parallel. HTML Parsing => CSSOM => evaluate script https://i.sstatic.net/uCX4s.png

On the other hand, Chrome presents an unexpected order HTML Parsing => evaluate script => CSSOM https://i.sstatic.net/qi73a.png

Therefore, I transformed the inline script to external, resulting in Chrome working as anticipated HTML Parsing => CSSOM => evaluate script

<html>
<head>
<style>
  h1 {color:red;}
  p>p {color:blue;}
  p>p>p {color:blue;}
  p>p>p>p {color:blue;}
  p>p>p>p>p {color:blue;}
  p>p>p>p>p>p {color:blue;}
  p>p>p>p>p>p>p {color:blue;}
  p>p>P>p>p>p>p>p {color:blue;}
</style>
</head>
<body>

<h1>A heading</h1>
<p>A paragraph.</p>
<p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
</body>
<script src="test.js"></script>
</html>

https://i.sstatic.net/reVyN.png

Understanding the optimization process

With inline script, it tends to execute faster than recalculating styles even if it doesn't alter your DOM or CSSOM, followed by another round of style recalculation after HTML Parsing concludes in both Chrome and IE11.

<html>
<head>
<style>
  h1 {color:red;}
  p>p {color:blue;}
  p>p>p {color:blue;}
  p>p>p>p {color:blue;}
  p>p>p>p>p {color:blue;}
  p>p>p>p>p>p {color:blue;}
  p>p>p>p>p>p>p {color:blue;}
  p>p>P>p>p>p>p>p {color:blue;}
</style>
</head>
<body>

<h1>A heading</h1>
<p>A paragraph.</p>
<p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg"></div>
    <script>
      var cnt=0
      while(cnt++ <=9999999){} 
    </script>
</body>
<!-- <script src="test.js"></script> -->
</html>

https://i.sstatic.net/NmwNx.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue 3 now allows for disabling the automatic renaming of CSS properties like "top/bottom/left/right" to "inset"

I noticed that Vue (or maybe Vite) automatically changes my css style attributes from "top: 0; right: 0; left: 0; bottom: 0;" to "inset: 0px;" However, this adaptation doesn't work well for older browsers that do not support the i ...

Tips for resizing images to fit within a TD cell in an HTML table

Currently, I have an issue with the image display within a TD element. Despite setting a specific width for the TD, the image appears to be wider than intended. Could you offer a solution to this problem? ...

Differences between JavaScript's window.onload and body.onload functionsWhen

My inquiry is similar yet slightly distinct from the one queried here: window.onload vs <body onload=""/> The comparison in that prior query was between utilizing window.onload and inline js. My question pertains to the disparity between ...

Achieve the effect of "background-attachment: fixed" using a div element

I am attempting to replicate a similar effect as seen here, which is accomplished using the CSS property background-attachment:fixed. However, I want to achieve this effect using div elements instead. For instance, could I apply this effect to an h1 tag? ...

Passing a date string from the Controller to JavaScript using the AJAX method

Below is the controller I have written: [HttpPost] public JsonResult GetTrackList(POS_model item) { //item.item_code //item.track_type if (item.track_type != "Regular") { POS pos = new POS(); ...

Can you explain the purpose of the behavior: url(); property in CSS?

While browsing the web, I came across a CSS property that caught my eye. It's called behavior, and it looks like this: #element{ behavior: url(something.htc); } I've never used or seen this property before. It seems to be related to Internet ...

PubNub's integration of WebRTC technology allows for seamless video streaming capabilities

I've been exploring the WebRTC sdk by PubNub and so far, everything has been smooth sailing. However, I'm facing a challenge when it comes to displaying video from a client on my screen. Following their documentation and tutorials, I have writte ...

Organizing entries based on the quantity of attached documents

I am currently working with mongodb and mongoose. I have a situation where users can create ratings and reviews for products. I want to retrieve the review of the product that has received the highest number of votes. Is this achievable in mongo? The data ...

Steps to designate a character depending on the frequency of its duplication within an array

I have a series of values in an array that I need to go through and assign incremental numerical values, starting from 1. If the same value appears more than once in the array, I want to append the original assigned number with the letter A, and then B, ac ...

Executing SendKeys on a div element with the attribute coleditable="true" in Selenium and C#

I am facing a challenge with an element that I am unable to input text into. <div class="floatstart gridcell grideditablefield" colname="Items" coltype="string" coleditable="true" val="" style="widt ...

Make sure to keep Vue-Cookies intact even when closing the browser or tab

I have integrated vue-cookies into my Vue application. The code I'm using to store a cookie is as follows: $cookies.set('authUser', authUserObj); The object authUserObj contains the access_token. However, when I close and reopen the ta ...

Sending input values from textboxes to the Controller

I currently have the following code snippets: Home Controller: public IActionResult Index() { return View(); } public ActionResult Transfer() { string path = @Url.Content(webRootPath + "\\SampleData\\TruckDtrSource.json&q ...

What is the best way to loop through an object while keeping track of its value types

I have a JSON file containing UI adjustments sourced from the API: interface UIAdjustmentsJSON { logoSize: number; themeColor: string; isFullScreen: boolean; } To simplify things, let's utilize a static object: const adjustments: UIAdjust ...

"Keep an eye on the server with Backbone.js by running periodic checks

In an effort to keep my backbone application constantly checking the server for model updates, I aim to create a system similar to Twitter's auto-refresh feature for new tweets. Currently, I am connecting to an external application through their API ...

Create a layout using CSS that features two columns. The left column should be fluid, expanding to fill all remaining space, while the right column should be fixed

I need to ensure that the Online Users div always remains at a fixed size of 200px, while allowing the chat window next to it to resize dynamically based on available space. Essentially, I want the chat window to adjust its width as the window is resized, ...

What is the process for making a POST request with the Google Chrome Puppeteer library?

Hello everyone, I'm currently attempting to make a POST request using the puppeteer headless chrome library. I'm running into some issues with the code below and can't seem to figure out what's wrong. // Obtain the csrf token ...

Implementing a Singleton Pattern in ReactJS using Context API for Asynchronous Operations

My current implementation involves using a hook: function useFollowUser() { const isFollowing = useRef(false); return (userId) => { if(isFollowing.current) return; // mutual exclusion isFollowing.current = true; ... updat ...

"Exploring the density of the xAxis in Highcharts

Currently, I am incorporating Highcharts into my jsp. Typically, when using Highcharts, we are able to create charts with all points evenly spaced along the x-axis. However, in this instance, I am interested in setting the points based on their x-values ...

Transforming ASP.NET MVC IEnumerable view model into a JSON array of elements

My goal is to develop a dynamic calendar in ASP.NET MVC that pulls event data from a database to populate it. Right now, the calendar is set up to read a json array of objects, but I am facing an issue with converting my ViewModel data into a format that t ...

How can I create distinct component IDs effectively with the Catberry Framework?

When working with Catberry, it is essential that all components have unique IDs. How can you ensure that each ID remains distinctive even within a complex structure of nested components? ...