20
CSS, JavaScript, and blocking web page parsing
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.
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:
<!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.
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.
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.
Here and further, we will use the following color symbols.
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.
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.
Let's experiment with async
the and attributes defer
. Let's start with the next page:
<!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
:
Promise.resolve().then((res) => {
console.log('index1');
return res;
});
File index2.js
:
Promise.resolve().then((res) => {
console.log('index2');
return res;
});
When this page loads, the JS console gets what is shown below.
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>
:
<!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.
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?
20