Objective
Whether the current JavaScript code is embedded or in an outside chain file, the download and render of the page must stop to wait for the script to complete. The longer the JavaScript executes, the longer the browser waits to respond to user input. The reason that browsers block when downloading and executing scripts is that scripts can alter the namespaces of pages or JavaScript, which affect the content of subsequent pages. A typical example is to use in a page document.write()
, such as Listing 1
Listing 1 Examples of JavaScript code inline
When a browser encounters a <script> tag, the current HTML page does not know whether JavaScript will add content to <p> tags, or introduce other elements, or even remove the tag. Therefore, the browser stops processing the page, executes the JavaScript code before continuing parsing and rendering the page. The same situation happens when you use the SRC attribute to load JavaScript, the browser must first take the time to download the code in the outer chain file, and then parse and execute it. In this process, page rendering and user interaction are completely blocked.
Script Location
The HTML 4 specification states that <script> tags can be placed in
Listing 2 example of a low-efficiency script location
However, this conventional approach hides serious performance problems. In the example in Listing 2, when the browser resolves to the <script> tag (line 4th), the browser stops parsing the content, and then downloads the script file first and executes the code, which means that the Styles.css style file and <body> Tags can not be loaded, because the <body> tag can not be loaded, then the page will naturally be unable to render. So the page is blank until the JavaScript code is fully executed. Figure 1 describes the download process for scripts and style files during page loading.
Figure 1 Loading and execution of JavaScript files blocking downloads of other files
We can find an interesting phenomenon: the first JavaScript file started downloading, while blocking other files on the page to download. Also, from SCRIPT1. JS download completed to script2.js began to download there is a delay, this time is exactly the Script1.js file implementation process. Each file must wait until the previous file has been downloaded and completed before the download begins. When these files are downloaded individually, the user sees a blank page.
JavaScript files are allowed to be downloaded in parallel from IE 8, Firefox 3.5, Safari 4, and Chrome 2. This is good news because the <script> tag does not block other <script> tags when downloading external resources. Unfortunately, the JavaScript download process still blocks downloads of other resources, such as style files and pictures. Although the script's download process does not affect each other, the page must still wait for all JavaScript code to be downloaded and executed to continue. Therefore, although the latest browsers improve performance by allowing concurrent downloads, the problem has not been fully resolved and scripting blocking remains a problem.
Because the script blocks downloads of other resources on the page, it is recommended that all <script> labels be placed at the bottom of the <body> tag as much as possible to minimize the impact on the entire page download. For example, listing 3
Example of the code drop location recommended in Listing 3
<script type= "Text/javascript" src= "Script1.js" defer></script>
<script> labels with defer properties can be placed anywhere in the document. The corresponding JavaScript file will start downloading when the page resolves to the <script> tag, but will not execute until the DOM is loaded, which is before the OnLoad event is triggered. When a JavaScript file with the defer attribute is downloaded, it does not block other browsers ' processes, so such files can be downloaded in parallel with other resource files.
Any <script> element with the defer attribute will not be executed until the DOM completes loading, both inline and in-chain scripts. The example in Listing 5 shows how the Defer property affects script behavior:
Listing 5 The effect of the defer property on the scripting behavior
This code pops up three dialog boxes during page processing. Browsers that do not support defer properties are in the pop-up order: "Defer", "script", "load". In browsers that support defer properties, the pop-up order is: script, defer, load. Note that the <script> element with the defer property is not followed by the second, but is invoked before the OnLoad event is triggered.
If your target browser includes only Internet Explorer and Firefox 3.5, then the defer script is really useful. If you need to support multiple browsers across the domain, there is a more consistent approach to implementation.
HTML 5 defines a new extended attribute for the <script> tag: Async. It functions like defer, can load and execute scripts asynchronously, and does not block the loading of pages because of loading scripts. However, it is important to note that, in the case of async, JavaScript scripts are executed as soon as they are downloaded, so they are probably not executed in the original order. If JavaScript scripts are dependent before and after, using async is likely to be an error.
Dynamic scripting elements
The Document Object Model (DOM) allows you to dynamically create almost all of the document content of HTML using JavaScript. <script> elements, like other elements of the page, can be created very easily through standard DOM functions:
Listing 6 creating <script> elements from standard DOM functions
var script = document.createelement ("script");
Script.type = "Text/javascript";
SCRIPT.SRC = "Script1.js";
document.getElementsByTagName ("Head") [0].appendchild (script);
The new <script> element loads the script1.js source file. This file starts downloading immediately after the element has been added to the page. The point of this technique is that no matter where you start the download, the download and run of the file will not block other page processing. You can even place the code in the
When a file is downloaded using a dynamic script node, the returned code is usually executed immediately (except for Firefox and Opera, they will wait for all previous dynamic script nodes to finish executing). This mechanism works fine when the script is a "self run" type, but it can cause problems if the script contains only the interfaces that are invoked by other script calls on the page. In this case, you need to track the completion of the script download and whether it is ready. You can use the dynamic <script> node to emit events to get relevant information.
Firefox, Opera, Chorme and Safari 3+ send a onload event after the <script> node is received. You can listen to this event to get a script-ready notification:
Listing 7 loading a JavaScript script by listening to the OnLoad event
var script = document.createelement ("script")
Script.type = "Text/javascript";
Firefox, Opera, Chrome, Safari 3+
script.onload = function () {
alert ("Script loaded!");
SCRIPT.SRC = "Script1.js";
document.getElementsByTagName ("Head") [0].appendchild (script);
Internet Explorer supports an alternative implementation that emits a ReadyStateChange event. The <script> element has a readyState attribute whose value changes as the process of downloading an external file is changed. ReadyState has five values:
1, "uninitialized": Default state
2, "Loading": Download start
3, "loaded": Download complete
4, "interactive": Download complete but not yet available
5, "complete": all data is ready
The Microsoft document says that in the life cycle of the <script> element, these readyState are not necessarily all present, but do not indicate which values will always be used. In practice, we are most interested in the state of "loaded" and "complete". Internet Explorer is not consistent with the final state represented by these two readyState values, sometimes <script> elements get "loader" but never "complete", but in other cases "complete" Rather than "loaded". The safest way to do this is to check both states in the ReadyStateChange event and, when one of the states appears, to delete the ReadyStateChange event handle (guarantee that the event will not be processed two times):
Listing 8 loading JavaScript scripts by checking the ReadyState state
var script = document.createelement ("script")
Script.type = "Text/javascript";
Internet Explorer
script.onreadystatechange = function () {
if (script.readystate = = "Loaded" | | Script.readystate = = "complete") {
script.onreadystatechange = null;
Alert ("Script loaded.");
}
;
SCRIPT.SRC = "Script1.js";
document.getElementsByTagName ("Head") [0].appendchild (script);
In most cases, you want to invoke a function to implement the dynamic loading of JavaScript files. The following function encapsulates the functionality required by the standard implementation and IE implementations:
Listing 9 is encapsulated by a function
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);
}
This function receives two parameters: The URL of a JavaScript file, and a callback function that fires when JavaScript receives completion. Property checks are used to determine which event to monitor. The final step is to set the SRC attribute and add the <script> element to the page. This loadscript () function uses the following methods:
List ten Loadscript () function use method
Loadscript ("Script1.js", function () {
alert (' File is loaded! ');
});
You can dynamically load many JavaScript files on a page, but be aware that browsers do not guarantee the order in which files are loaded. Of all the mainstream browsers, only Firefox and Opera guarantee that the script executes in the order you specify. Other browsers will download and run different code files in the order that the server returns them. You can concatenate the download operations together to ensure their order, as follows:
Listing 11 loads multiple JavaScript scripts through the Loadscript () function
Loadscript ("Script1.js", function () {
loadscript ("Script2.js", function () {
loadscript ("Script3.js"), function () {
alert ("All files are loaded!");
});
};
This code waits for Script1.js to be available before loading the script2.js, and then Script2.js is available before loading script3.js. While this approach works, there is a lot of trouble downloading and executing files. If the order of multiple files is important, it is a better idea to connect the files to a file in the correct order. Standalone files can download all the code at once (since this is done asynchronously, there is nothing to lose by using a large file).
Dynamic script loading is the most common pattern in non-blocking JavaScript downloads because it can be used across browsers and is easy to use.
Using XMLHttpRequest (XHR) objects
This technique first creates a XHR object, then downloads the JavaScript file, and then injects the JavaScript code into the page with a dynamic <script> element. Listing 12 is a simple example:
Listing 12 loading JavaScript scripts with the XHR object
var xhr = new XMLHttpRequest ();
Xhr.open ("Get", "Script1.js", true);
Xhr.onreadystatechange = function () {
if (xhr.readystate = 4) {
if (xhr.status >= && xhr.status ; 300 | | Xhr.status = = 304) {
var script = document.createelement ("script");
Script.type = "Text/javascript";
Script.text = Xhr.responsetext;
Document.body.appendChild (script);}}
;
Xhr.send (NULL);
This code sends a GET request to the server to obtain the Script1.js file. The onReadyStateChange event handler checks that the readyState is not 4, and then checks that the HTTP status code is not valid (2XX is a valid response, and 304 represents a cached response). If a valid response is received, a new <script> element is created, and its Text property is set to the ResponseText string received from the server. Doing so actually creates a <script> element with inline code. Once the new <script> elements are added to the document, the code will be executed and ready to be used.
The main advantage of this approach is that you can download JavaScript code that is not executed immediately. Since the code returns outside the <script> tag (in other words, it is not bound by the <script> tag), it is not automatically executed after downloading, which allows you to postpone execution until everything is ready. Another advantage is that the same code does not throw an exception in all modern browsers.
The main limitation of this approach is that JavaScript files must be placed in the same domain as the page and cannot be downloaded from a CDN (Cdn refers to the content delivery network (Delivery network), so large web pages usually do not use XHR script injection techniques.
Add a few functions that you normally use
function Loadjs (URL, callback, CharSet) {
var head = document.getelementsbytagname (' head ') [0];
var script = document.createelement ("script");
if (!! CharSet) Script.charset = "Utf-8";
script.src = URL;
Script.onload = Script.onreadystatechange = function () {
var f = script.readystate;
if (f && f!= "loaded" && F!= "complete") return;
Script.onload = Script.onreadystatechange = null;
Head.removechild (script) if (callback) {
callback () | | callback
};
};
Head.appendchild (script);
/JS synchronous load Function getscripts (i, Linkarray, fn) {env | | getEnv ();
var script = document.createelement (' script ');
Script.type = ' Text/javascript ';
SCRIPT.SRC = Linkarray[i]; var head = Document.head | |
document.getElementsByTagName (' head ') [0];
Head.appendchild (script); if (env.ie && ' onreadystatechange ' in script &&!) (' Draggable ' in script ') {//ie browser loads Script.onreadystatechange = function () {if (/loaded|complete/.test) in the following ways (SCRIPT.R
Eadystate)) {script.onreadystatechange = null;
if (i = = = Linkarray.length-1) {if (FN) {fn ();
} else {getscripts (++i, Linkarray, FN);
}
}
};
}else{script.onload = function () {if (i = = linkarray.length-1) {if (FN) {fn ();
} else {getscripts (++i, Linkarray, FN);
}
}; }//JS dependencies are loaded sequentially getscripts (0, [' http://caibaojian.com/demo/base.js ', ' http://caibaojian.com/demo/reset.js '], func tion () {alert (' callback ');});
Summarize
There are several ways to reduce the impact of JavaScript on performance:
Placing all <script> tabs at the bottom of the page, before </body> closing the tabs, ensures that the page has been rendered before the script executes.
Merge scripts as much as possible. The fewer <script> tabs in the page, the faster the load and the quicker the response. This is true whether it is an external chain script or an inline script.
A method for downloading JavaScript scripts with no blocking:
Use the defer properties of the <script> tag (IE and Firefox version 3.5 only);
Use dynamically created <script> elements to download and execute code;
Use the XHR object to download JavaScript code and inject it into the page.
By using these strategies, you can greatly improve the actual performance of Web sites and applications that require a lot of JavaScript.
The above is JavaScript Performance optimization summary of the load and implementation of the full content, I hope to help you.