The performance of Javascript in the browser can be said to be the most important usability issue that front-end developers have to face.
Among Yahoo's Yslow23 rules, one of them is to put JS at the bottom. The reason is that, in fact, most browsers use a single process to process multiple tasks such as UI and update Javascript runs, and only one task is executed at the same time. How long does Javascript run, how long will it take to wait before the browser is idle to respond to user interaction.
From a basic perspective, this means that the appearance of the <script> tag causes the entire page to wait due to script parsing and running. Regardless of whether the actual JavaScript code is inlined or contained in an irrelevant external file, the page download and parsing process must be stopped and wait for the script to complete these processing before continuing. This is an essential part of the page life cycle, because the script may modify the page content during runtime. A typical example is the document.write() function, for example:
The code copy is as follows:
<html>
<head>
<title>Script Example</title>
</head>
<body>
<p>
<script type="text/javascript">
document.write("The date is " + (new Date()).toDateString());
</script>
</p>
</body>
</html>
When the browser encounters a <script> tag, as in the HTML page above, it is impossible to predict whether JavaScript adds content to the <p> tag. Therefore, the browser stops, runs this JavaScript code, and then continues to parse and translate the page. The same thing happens when loading JavaScript using the src property. The browser must first download the code for the external file, which takes some time, and then parse and run this code. During this process, page parsing and user interaction are completely blocked.
Because the script blocks the download process of other page resources, the recommended method is: place all <script> tags as close to the bottom of the <body> tag as possible to minimize the impact on the entire page download. For example:
The code copy is as follows:
<html>
<head>
<title>Script Example</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
<-- Example of recommended script positioning -->
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="file3.js"></script>
</body>
</html>
This code shows where the recommended <script> tag is located in the HTML file. Although script downloads are blocked between each other, the page has been downloaded and displayed in front of the user, and the speed of entering the page will not appear too slow. This is what mentioned above to put JS to the bottom.
In addition, Yahoo! creates a "federal handle" for his "Yahoo! User Interface, YUI" library, which is implemented through their "Content Delivery Network (CDN). Any website can use a "federal handle" URL to indicate which files are included in the YUI file package. For example, the following URL contains two files:
The code copy is as follows:
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.7.0/build/yahoo/yahoo-min.js&2.7.0/build/event/event-min.js"></script>
This URL calls the yahoo-min.js and event-min.js files in version 2.7.0. These files are two separate files on the server, but when the server receives this URL request, the two files will be merged together and returned to the client. In this way, two <script> tags are no longer needed (one file is loaded for each tag), and one <script> tag can load them. This is the best way to include multiple external Javascript in HTML pages.
Noblocking Scripts
The above is the best way to load multiple Javascript scripts in the initial state of the page. Javascript tends to block certain browser processing processes, such as http requests and interface refreshes, which are the most significant performance problems faced by developers. Keeping Javascript files short and limiting the number of http requests is just the first step to creating a responsive web application.
But such as large web pages with a lot of Js code, keeping the source code short is not always the best choice. So, non-blocking scripts came into being, what we need is to gradually add javascript to the page, which will not block the browser to some extent.
The key to not blocking scripts is to load the Javascript source code after the page is loaded, which means that the code download starts after the window's load event is issued.
Related explanations:
The load event of window will only be fired once and only once after the page is loaded.
window.onload=function(){} must wait for all content in the web page to load (including all associated files of elements, such as pictures) to be executed, that is, Javascript can access any element in the page at this time.
The following methods are:
Deferred Scripts Deferred Scripts
Html4 defines an extended attribute for the <script> tag: defer.
This defer attribute indicates that the script contained in the element does not intend to modify the DOM, so the code can be executed later. The defer attribute is only supported by Internet Explorer 4+ and Firefox 3.5+, and it is not an ideal cross-browser solution. On other browsers, the defer attribute will be ignored. Therefore, the <script> tag will be processed in the normal default way, which means it will cause blockage. If supported by various mainstream browsers, this is still an effective solution.
The code copy is as follows:
<script type="text/javascript" src="file1.js" defer></script>
A <script> tag with the defer attribute can be placed anywhere in the document, and it starts the download when it is parsed until the DOM loads (before the onload event handle is called). When a defer Javascript file is downloaded, it does not block other processing processes in the browser, so these files can be downloaded in parallel with other resources.
You can use the following code to test whether the browser supports the defer attribute:
The code copy is as follows:
<html>
<head>
<title>Script Defer Example</title>
</head>
<body>
<script defer> alert("defer");</script>
<script> alert("script"); </script>
<script> window.onload = function(){ alert("load");}; </script>
</body>
</html>
If the browser does not support defer, the order of the pop-up dialog boxes is "defer", "script", and "load".
If the browser supports defer, the order of the pop-up dialog boxes is "script", "load", "defer".
Dynamic Script Elements
DOM allows us to dynamically create almost all document content of HTML using Javascript, and a new <script> element can be created very easily through standard DOM:
The code copy is as follows:
1 var script = document.createElement ("script");
2 script.type = "text/javascript";
3 script.src = "file1.js";
4 document.body.appendChild(script);
The new <script> element loads the file1.js source file. Download this file immediately after the element is added to the page. The key point of this technology is that no matter where the download is started, the download and running of the file will not block other page processing.
When a file is downloaded using a dynamic script node, the returned code is usually executed immediately (except Firefox and Opera, which will wait for all previous dynamic script nodes to be executed).
In most cases, we hope to call a function to implement dynamic download of Javascript files. The following function encapsulation implements standard implementations and IE implementations:
The code copy is as follows:
function loadScript(url, callback){
var script = document.createElement ("script");
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
}
else { //Others
script.onload = function(){ callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("file1.js", function(){ //Call
alert("File is loaded!");
});
This function accepts two parameters: the Url of the Javascript file and a callback function that is triggered when Javascript reception is completed. Attribute checking is used to determine which event to monitor. The last step is to src attribute and add the javascript file to the head.
Dynamic script loading is the most commonly used pattern in non-blocking Javascript downloads because it can be cross-browser and is easy to use.
XMLHttpRequest Script Injection XHR script injection
Another way to get scripts in a non-blocking way is to inject scripts into the page using the XMLHttpRequest(XHR) object. This technique first creates an XHR object, then downloads a Javascript file, and then injects Javascript code into the page with a dynamic <script> element. Look at the demo:
The code copy is as follows:
var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ // Check the http status code
var script = document.createElement("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null);
This code sends a file get request to the server to get file1.js. The onreadystatechange event handler checks whether readyState is 4, and then checks whether the http status code is valid (200 means confirming that the client request has been successful, 2xx means valid response, and 304 means a cached response). If a valid response is received, a new <script> element is created and its text attribute is set to the responseText string received from the server. Doing so will actually create a <script> element with inline code, and once a new <script> element is added to the document, the code will be executed and ready to be used.
The advantage of this method is that it has good compatibility and you can download Javascript code that is not executed immediately. Since the code returns outside the <script> tag, it will not be executed automatically after downloading, which allows you to postpone the execution.
The determination of this method is subject to browser homologous restrictions. Javascript files must be placed in the same domain as the page and cannot be downloaded from the CDN (Content Delivery Network). For this reason, large web pages usually do not use XHR script injection technology.
Recommended Noblocking Pattern Recommended Noblocking Pattern
The recommended method of loading a large amount of Javascript to a page is divided into two steps:
The first step includes the code required to dynamically load Javascript, and then load the part except Javascript required for page initialization. This part of the code is as small as possible and may only include the loadScript() function. It downloads and runs very quickly and will not cause much interference to the page.
The second step is to use it to load the rest of Javascript after the initial code is ready.
For example:
The code copy is as follows:
1 <script type="text/javascript" src="loader.js">
2 </script> <script type="text/javascript">
3 loadScript("the-rest.js", function(){
4 Application.init();
5 });
6
7 </script>
Place this code before the body's close tag</body>. The benefit of doing this is that first, this ensures that Javascript runs without affecting other parts of other pages to display. Secondly, when the second part of Javascript file is downloaded, all the necessary DOMs for the application have been created and ready to be accessed, avoiding the use of additional event processing (such as window.onload) to know whether the page is ready.
Another option is to embed the loadScript() function directly into the page, which can reduce the overhead of an http request. For example:
The code copy is as follows:
1 <script type="text/javascript">
function loadScript(url, callback){
var script = document.createElement ("script");
script.type = "text/javascript";
if (script.readyState){ //IE script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("the-rest.js", function(){
Application.init();
});
</script>
Once the page initialization code is downloaded, you can also use the loadScript() function to load the additional functional functions required by the page.
Introducing a common tool, Ryan Grove of Yahoo! Search created the LazyLoad library (see: http://github.com/rgrove/lazyload/). LazyLoad is a powerful loadScript() function. LazyLoad only has about 1.5KB after scaling. Examples of usage are as follows:
The code copy is as follows:
<script type="text/javascript" src="lazyload-min.js"></script>
<script type="text/javascript">
LazyLoad.js("the-rest.js", function(){
Application.init();
});
</script>
Summary
1. Place all <script> tags at the bottom of the page, close to the close tag</body>. This method ensures that the page is parsed before the script is run.
2. Pack the scripts in groups. The fewer <script> tags on a page, the faster the page will load and respond faster. This is true for both external script files and inline code.
3. There are several ways to download Javascript using non-blocking methods:
1). Add a defer attribute to the <script> tag
2). Dynamically create the <script> element, use it to download and execute the code
3). Use XHR object to download the code and inject it into the page
Through the above strategy, the actual performance of netizens who use Javascript code can be greatly improved.
Reference book "High Performance Javascript".