Non-blocking loading JS script for front end performance

Source: Internet
Author: User
Tags script tag

The blocking behavior of the script tag affects the performance of the page because the browser does not do other things in the process of downloading scripts, parsing, or executing, such as rendering pages, responding to user events, and so on. This is done because the JavaScript code that is being executed can change various operations such as page elements , Modify Styles , Add or delete events , and the dependencies between the most critical scripts. The browser must wait for the currently executed script to complete before it can be followed up.

Script Blocking two load modes

JavaScript scripts in HTML pages are added in two ways
-The script tag is used inline to the HTML page, and the page executes the JS code in order from top to bottom, and subsequent HTML content is blocked.
-Use the SRC attribute of the script tag to load the JS file externally, which requires the browser to query the cache of the corresponding file, and if it is not available, re-make the HTTP request, which will result in network latency and post-download parsing and execution, which will block the page.

Browser features

In general, most browsers support the parallel download of HTML, CSS, pictures and other elements, but for the same domain name resources, the browser default maximum number of concurrent download is limited, generally 4. In addition, for JavaScript scripts, the browser does not support parallel downloads, and when a script is downloaded and parsed and executed, the latter can be executed.
Browsers are guaranteed not to be able to download multiple scripts in parallel, in order to prevent two dependent scripts from being reversed in the execution order of the browser, which throws a variable, function undefined error. HTML content is also changed. Therefore, scripts must be executed sequentially, but this does not mean that they must be downloaded in sequence.
IE8 is the first browser to support parallel download of JavaScript scripts, which makes it much faster to load multiple scripts, but this does not solve the blocking problem of script execution. When A.js and b.js are downloaded in parallel, they still have to parse and execute sequentially, which must block the browser's other behavior, that is, after this period of time to download the subsequent images, CSS, iframe and other elements. Chrome and Safari 4+ browsers are similar to IE8 and will download scripts in parallel but not
Therefore, the ultimate goal is to download scripts in parallel, but also to download other elements without blocking problems. This is illustrated by the loading of external script files.

Non-blocking loading of external scripts

In order to avoid the blocking problem of the script, the simplest way is to say that all JavaScript script inline to the HTML, put the script on all the visible elements of the last surface, you can avoid this problem, but for large JS files and cache js file considerations, this problem needs to be compromised. For external JS file request, mainly in the following ways

XHR Eval

The JS script file is obtained asynchronously from the server using the XMLHttpRequest object, and the response content is executed using the Eval function of the JavaScript language when the response is complete.
Advantage: The JS file of the asynchronous request does not block the download of other elements (pictures, CSS, etc.), and the script executes after the asynchronous download is complete. The browser does not display "wait".
Disadvantage: The requested JS file must be with the main page under the same domain name, which is inconvenient for CDN or multi-domain processing. Execution order cannot be guaranteed.

varfunction(){    if4200){        //依赖文件队列处理        eval(xhrObj.responseText);        //后续处理    }};xhrObj.open(‘GET‘‘a.js‘true);xhrObj.send(‘‘);

Generally in order to ensure the asynchronous loading of the JS file dependency, you need to manually save the dependent file queue, so that it executes in a dependent order.

XHR Injection

Similar to XHR eval, XHR injection inserts the asynchronously obtained content into the DOM element using the dynamically created script tag. The actual test shows that using the Eval method is slower than this method.

var  xhrobj = Getxhrobject (); Xhrobj.onreadystatechange = function   ()  { if  (xhrobj.readystate = = 4  && xhrobj.status = 200 ) {//dependent file queue processing  var  script = document.createelement (); document.getElementsByTagName ( ' head ' ) [0 ]. AppendChild (script); Script.text = Xhrobj.responsetext; //follow-up Processing }}; Xhrobj.open ( ' GET ' ,  ' a.js ' , true ); Xhrobj.send ();  

The pros and cons of this approach are similar to XHR eval, but may be faster.

Script in Iframe

The IFRAME can be downloaded in parallel with other elements of the main page and will not block. But the IFRAME is to contain other HTML pages, other HTML pages can also contain JS script, so you can load the JS script into an HTML file and then use the IFRAME non-blocking to load the HTML file.
Pros: Asynchronous load script, browser support good
Disadvantage: Need to be the same domain name as the main page, you need to convert the external JS file to HTML as the SRC attribute of the IFRAME. In addition, the IFRAME is a very heavyweight dom element. Execution order cannot be guaranteed. The browser will display "Wait".
The IFRAME itself can also be created dynamically using the JS script:

var_ = function(d){document.getElementById (d);};varRemoveNode = function(a) {   Try{typeofA = ="string"&& (A = _ (a)); A.parentnode.removechild (A)}Catch(b) {}};varAddevent = function(ele, event, call){Ele.addeventlistener? Ele.addeventlistener (event, call,!)1): A.attachevent? A.attachevent ("on"+ Event, call): a["on"+ Event] = call;};varLoadscriptbyiframe = function(ID, src){src = =NULL&& (src ="Javascript:false;"); RemoveNode (ID);varc = document.createelement (' iframe '); C.height =0; C.width =0; C.style.display ="None";    C.name = ID;    C.id = ID;    C.SRC = src; C.isready =!1; Addevent (c,"Load", function(){        if(! C.isready) {C.isready =!0;//The current script is loaded and executes other JS code}    });    Document.body.appendChild (c); Window.frames[id].name = ID;returnc;};

Scripts in the IFRAME and master pages need to be modified to access each other:
-Access the IFRAME from the main page

window.frames[0//使用framesdocument.getElementById(‘iframeID‘//使用getElementById
    • Accessing the main page from an IFRAME
function methodInIframe(){    var newDiv = parent.document.createElement(‘div‘);    parent.document.body.appendChild(newDiv);}
Script DOM Element

This method is the most used method, through the JS script dynamically create script tags inserted into the DOM, you can dynamically set the SRC attribute, and can be a different domain name JS file, general Baidu Statistics, CNZZ, Google The statistical code provided by Web site statistics tools such as analysis is used in this way and is the most widely known method of use.
Pros: You can cross-domain, creating a SCRIPT element does not block the download of other elements, and code implementation is simple and convenient.
Disadvantage: The downloaded script does not guarantee sequential execution, only in the Firefox browser under the order of execution, the other browser has a dependency conflict script file. The browser displays "Waiting".

var loadScriptByScriptDom(id, src, c){    removeNode(id);    var d = document.getElementsByTagName(‘head‘)[0],        e = document.createElement(‘script‘);    ‘utf-8‘;    e.id = id;    ‘text/javascript‘;    e.src = src;    d.appendChild(e);}
Script Defer

The script tag of IE browser supports the Defer property, and when this property is used, the browser will recognize that it will not immediately download the script tag for the JS file. When there is no document.write call in this JS file, and no other script depends on the file, then it can be used. IE will not block the download of other elements while downloading this file.
Advantages: Easy to implement, ensure the sequence of JS file execution, support cross-domain
Cons: The browser will display a "Wait" status, only the IE browser that supports the Defer property is applicable.

<script defer src="a.js"></script>
document.write Script Tag

In the JavaScript language, the write method of the document can be called to write content to the HTML DOM, which is only downloaded in parallel in IE, and other resources are still blocked during the download. is not a good way to solve.

document.write("<script type=‘text/javascript‘ src=‘a.js‘></script>")
Evaluation standard Browser "Wait" flag

The browser waits for the flags include: status bar, progress bar, tab icon, cursor shape, there are also blocking rendering and blocking onload event, the former is in the current download JS script after the visual content is blocked so that does not render, The latter is only triggered after all resources have been downloaded to finish rendering the page.
The "Wait" state of most browsers is triggered during loading using the SRC mode of script, so the user perceives that the page has not finished loading. However, these status identifiers are not triggered by the XHR-based XHR eval and XHR injection methods.

Execution order of multiple JS scripts

When loading multiple JS scripts using the above method, if there are dependencies between them, then it is necessary to ensure that their execution order is not changed, otherwise there will be a variety of undefined errors. In most cases, this is not only related to methods, but also browser-related, and the method of using the SRC attribute of script ensures that the order of execution is consistent with the order of arrangement in the page.
For IE browsers, the script defer and Document.Write script tag methods ensure that the order of execution is consistent with the order of arrangement.
The Firefox browser does not support the script defer property, and the Document.Write method cannot be downloaded in parallel. But the script Dom method can be executed in the Firefox browser in the order in which it is arranged in the page, but not by other browsers.
The XHR-based approach above does not guarantee the order of execution, but can then be guaranteed by manual processing of the download queue.

Conclusion

Based on the above-mentioned evaluation, the Document.Write method not only relies heavily on the browser, but also still blocks the subsequent resources, so it should be avoided, other ways for different browsers, and whether the order of execution and the "Wait" flag of the browser should be displayed. Need to be treated differently. The final version is as follows:

OS = function(){    varDom = document, ME = This; This. addevent = function(ele, event, call){Ele.addeventlistener? Ele.addeventlistener (event, call,!)1): A.attachevent? A.attachevent ("on"+ Event, call): a["on"+ Event] = call; }; This. Getxhrobject = function(){        varXhrobj =false;Try{xhrobj =NewXMLHttpRequest (); }Catch(e) {varMstypes = ["msxml2.xmlhttp.6.0","msxml2.xmlhttp.3.0","Msxml2.xmlhttp","Microsoft.XMLHTTP"];varL = mstypes.length; for(vari =0; I < L; i++) {Try{xhrobj =NewActiveXObject (Mstypes[i]); }Catch(e) {Continue; } Break; }        }finally{returnXhrobj; }    }; This. Loadscript = {Default: function(URL, onload){Me. Loadscript.        DomElement (URL, onload); }, DomElement: function(URL, onload){            varDomscript = Dom.createelement (' script '); domscript.src = URL;if(onload) {Domscript.onloaddone =false;                Domscript.onload = onload; Domscript.onreadystatechange = function(){                    if("Loaded"= = = Domscript.readystate && domscript.onloaddone) {Domscript.onloaddone =true;                    Domscript.onload (); }}} dom.getelementsbytagname (' head ')[0].appendchild (Domscript); }, Docwrite: function(URL, onload){document.write (' <SCR '+' IPT src= '+ URL +' "Type=text/javascript" ></scr '+' ipt> ');if(onload) {me.addevent (window,"Load", onload); }}, Queuedscripts:New Array(), Xhrinjection: function(URL, onload, isoredered){            varQ = Me. LoadScript.queuedScripts.length;if(isoredered) {varQscript = {response:NULL, Onload:onload, Done:false}; Me.            LOADSCRIPT.QUEUEDSCRIPTS[Q] = Qscript; }varXhrobj = Me.getxhrobject (); Xhrobj.onreadystatechange = function(){                if(Xhrobj.readystate = =4){if(isordered) {me.                         Loadscript.queuedscripts[q].response = Xhrobj.responsetext; Me.                    Loadscript.injectscripts (); }Else{Eval(Xhrobj.responsetext);if(onload) onload ();            }                }            }; Xhrobj.open (' GET 'Urltrue); Xhrobj.send ("'); }, Injectscripts: function(){            varQueue = Me. loadscript.queuedscripts;varlen = queue.length; for(vari =0; i < Len; i++) {varQscript = Queue[i];if(! Qscript.done) { Break; }Else{Eval(Qscript.response);if(Qscript.onload)                    {qscript.onload (); } Qscript.done =true; }            }        },    };};//end of OS

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Non-blocking loading JS script for front end performance

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.