CSS, JavaScript, and blocking web page parsing
Tags: webdev, css, javascript, programming
Published: 2021-06-19 18:42:02

Recently, I came across an article about the problem of loading CSS files, which slows down the processing of page materials. I read that article, trying to learn something new, but it seemed to me that what it said was not quite true. So I did my own research on this topic and experimented with loading CSS and JavaScript.

# Can loading CSS resources block page parsing?

First of all, I will say that the question in the title of this section can, without any doubt, be answered positively. Loading CSS files can not only block HTML code parsing, but also prevent JavaScript code from executing.

To begin with, I suggest experimenting. To do this, we will need to configure the browser accordingly. We will download the CSS file from the CDN, so we will limit the speed of working with the network in the Google Chrome browser. To do this , on the developer tools tabPerformance, change the parameter value Networkto Slow 3G. We will explore the next page:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            console.log('DOMContentLoaded');
        })
    </script>
    <script>
        console.log('script');
        Promise.resolve(1).then(res => {
            console.log('then');
        });
    </script>
</head>
<body>
    <h1>hello</h1>
</body>
</html>
```

We download the CSS file from the CDN, but since the Internet connection speed is artificially limited, it will take some time to load the styles. As a result, nothing gets to the JavaScript console before the CSS file is loaded, and the page content is not displayed on the screen. What we're seeing indicates that CSS loading is blocking other page content from being loaded and processed.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzqjqw97c5fbpvjicdvl.png) *Output of data to the JS console*

# Can loading and executing JS code block page parsing?

Loading and processing JS files, of course, blocks page parsing. However, to fix this problem, you can use attributes and tags when connecting scripts to the page `defer async <script>`. Now we will study their impact on page loading.

# Normal script loading and execution

If the tag `<script>` does not use `async` or attributes `defer` — the page content loading and processing process is performed as shown in the following diagram. Loading JS files and executing the code contained in them blocks HTML parsing.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wto267r95eoabxdlse07.png) *Using the `<script>` tag without the async and defer attributes*

Here and further, we will use the following color symbols.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h75qri4xvgsx1i7na7bs.png) *HTML parsing — HTML parsing; HTML parsing paused-HTML parsing suspended; Script download — Script loading; Script execution — Script execution*
 
## Using the `<script>` tag with the async attribute

When the browser processes a tag `<script>` with an attribute `async`, the JavaScript code is loaded asynchronously. The script code is executed immediately after loading. However, JS code execution blocks HTML parsing.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/et1gy6xvhrgde555zass.png) *Using the `<script>` tag with the async attribute*

## Using the `<script>` tag with the defer attribute

If the tag `<script>` contains an attribute `defer` — the script code is loaded asynchronously. However, after the code is loaded, it is executed only when the parsing of the HTML code is completed.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5md5z8bgfmyjdb1u5916.png) *Using the `<script>` tag with the defer attribute* 

# Experiments

Let's experiment with `async` the and attributes `defer`. Let's start with the next page:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DomContentLoaded</title>
</head>
<body>
    <script src="http://code.jquery.com/jquery-1.4.4.min.js">
    </script>
    <script src="./index.js"/> // 0
    <script src="./index2.js"/> // 2
    <script >
    console.log('inline');
        Promise.resolve().then(res=>{
            console.log('then');
        })
    </script>
    <div id="hello">hello world</div>
    
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            console.log('DOMContentLoaded');
        })
    </script>
    
</body>
</html>
```

This page, in addition to downloading the script `jquery-1.4.4.min.js` from the CDN, loads a couple of its own scripts - `index.js` and `index2.js`. Below is their code.

File `index.js`:
```js
Promise.resolve().then((res) => {
    console.log('index1');
    return res;
});
```

File `index2.js`:
```js
Promise.resolve().then((res) => {
    console.log('index2');
    return res;
});
```

When this page loads, the JS console gets what is shown below.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ftir71tt8anf9wi8jzp8.png) *Output of data to the JS console*

As a result, we have proof that loading and processing JS files blocks HTML code rendering. Messages output by scripts appear in the console before the message indicating that the DOM content has finished loading.

Now let's take a look at how scripts `<script>` that use the attribute in their tags behave `<async>`:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta data-fr-http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DomContentLoaded</title>
</head>
<body>
    <script async src="http://code.jquery.com/jquery-1.4.4.min.js">
    </script>
    <script src="./index.js"></script> 
    <script src="./index2.js"/></script>
    <script>
    console.log('inline');
        Promise.resolve().then(res=>{
            console.log('then');
        })
    </script>
    <div id="hello">hello world</div>
    
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            console.log('DOMContentLoaded');
        })
    </script>
    
</body>
</html>
```

Let's look at what is shown in the console.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tpyr7gzos37gmyn4ou1w.png) *Output of data to the JS console*
 
The jQuery library script is loaded asynchronously. What goes to the console is displayed there before it is loaded. If the library script loads too slowly, it won't interfere with parsing the HTML code. The message `DOMContentLoaded` can be displayed either before or after the async script is loaded and executed. And when the attribute `defer` is applied, the script will be loaded asynchronously, wait for the document materials to be processed, and then , but before the eventDOMContentLoaded, it will be executed.


Have you ever encountered problems with blocking the processing of web page content?