Explore true nonblocking loading JavaScript scripting technology, we will find a lot of unexpected secrets (reproduced)

Source: Internet
Author: User
Tags script tag



The image below is the HTTP request I recorded when I browsed Baidu homepage using Firefox and Chrome.






Here's the Firefox:








Here's the chrome:








Before browsing the homepage of Baidu, I will all clean out the cache of the browser, let this scene is closest to the first visit Baidu homepage scene.



In the Firefox request Waterfall diagram is very obvious: after the JavaScript file is downloaded, there is a period of time there is no network request processing, the time after the HTTP request will continue to execute, this idle time is the so-called HTTP request is blocked.



HTTP requests that are blocked in the browser are usually caused by JavaScript, because JavaScript is executed immediately after the download is complete, and JavaScript execution blocks other browser behavior. For example, blocking execution of other JavaScript and other HTTP requests. This will cause the page to load slowly, if this slow is obvious, at this time the user Action page will find that the page does not respond slowly, slow is the nightmare of site user experience.



I'm currently developing systems that often encounter JavaScript blocking page loading in the development environment, The main reason is that many of our site's static resources and scripts are independently extracted on a separate static resource server, while the local development environment simulates the static resource service environment is often very unstable (often down), and sometimes some new scripts are not updated to the development environment, so some JS script files are not properly retrieved , these problems cause the page load time these JS script will block the loading of the page, the browser will repeatedly try to request these JS files, until the request timed out to determine that the URL of the script is invalid, if you can not tolerate this wait in the middle, forcing the browser to close the request, Will find in the browser console a lot of scripts can not be found, so you can not set in the console JS code breakpoint debugging JS, if waiting for JS loaded, the time will be wasted, helpless under just find those invalid URL will be commented out, hey, As a result, it was annoying to commit the commented error code to the SVN server several times.



Regardless of the browser, whether it's a new version or an older version of the browser, they uphold the browser's single-threaded features, This feature seems to be a difficult rule, when we enter a URL address in the browser's address bar, access to a new page, the speed of the page is controlled by a single thread, which is called the UI thread, the UI thread will be based on the page resources (resources refers to CSS files, pictures, etc.) book Write the order to load the resources, load the resources that is using HTTP requests to obtain resources, such as CSS external files, HTML files and images, such as resources HTTP request processing completed also means that the resource loading end, but like the external JavaScript file is different, its loading process is divided into two steps, The first step is to load the CSS file and the image, is to execute an HTTP request to download the external JS file, but the JavaScript after the HTTP operation does not mean that the operation is complete, the UI thread will then execute it, if you develop the page JS code execution time is too long, then the user will Obviously feel the delay of the page. Why can't the browser split the loading process of the JavaScript code into two parallel processes, so that you can make the most of the time to complete the HTTP request, so it doesn't improve the load efficiency of the page? The answer to this question is of course negative, JavaScript is a programming language, JS code is intelligent, it can do logical work, but also by manipulating page elements to change the page UI effect, if we ignore the impact of JavaScript on the UI, let it delay execution, The result is a confusing page display. So what kind of chaos does he have? The description of this confusion is as follows:



The simplest and best understood and best-mastered ideas are linear thinking, for the browser UI display to be linear thinking that the resources placed in front of the page will be loaded and executed, the browser will also think that the previous step of the content is likely to be the next page to display the premise, if the browser stopped the execution of a code in the middle, It is possible that the final rendering of the page is different from the designer's design, so that we cannot develop the correct page. And according to linear thinking when you touch the page UI effect problems, you can easily locate the problem, if we put the JS code to separate the loading and execution, which is like the linear idea into a tree structure, you master the idea of page loading and solve the UI load problem will become more difficult, A lot of people will be crazy and confused, so I'm here to say chaos.



In summary, the JS script download and execution is a complete operation, is absolutely cannot be fragmented.



browser in order to improve the user experience, speed up the implementation of the UI thread is an unavoidable problem, it seems to split JS download and execution is not feasible, if the browser to change the way, this way is to download multiple resources at the same time, we look at the same domain name, Firefox can download two images at the same time, chrome can download 4 static resources at the same time, but this is for the image and CSS files, for the JS file seems to be one after another download, download one to execute one, but in IE8 above version, JS can be loaded in parallel with the picture, IE to improve the efficiency of the JS file download, but to JS execution time or strictly in accordance with the order of execution.



multiple HTTP connections parallel download resources are like multiple threads doing a task together, if there are more parallel HTTP connections, So there are more HTTP resources to be downloaded at the same time, but the browser provides parallel execution of the HTTP connection is too little, such as the above Firefox two, Chrome is only 4, how to break through the browser's limit of the number of connections? The method is very simple is common, stable static resources on a static resource server, from a unified domain name to provide, the domain name and the main request domain name is not the same, the principle is because the browser only through the domain name to limit the number of connections, if a page has two different domains, Then the number of concurrent HTTP requests will also become twice times. This approach is a bit of a browser, is the programmer to discover the characteristics of the browser summed up the technology, it is similar to a hack technology, and hack technology will not be standard technology, so it must have its bottleneck area, so this technology will have a degree, browser limit the number of requests is absolutely not unprovoked, we see hundred Degree page parallel download picture of the version of the HTTP protocol is 1.1,http1.1 feature is a long connection, the advantage of long connection is that the page and the server frequently interactive time is very efficient, but the browser's page operation is not always a frequent request for servers, and in order to load static resources and create a lot of long connections, Servers will have to maintain a large number of useless long connections, the pressure on the server is conceivable. In contrast to the http1.0 protocol, it does not use long connections, but rather short connections, so earlier versions of the browser would have more connections to the HTTP1.0 protocol than http1.1 connections, so some sites would The HTTP protocol version provided by the static resource server is reduced to 1.0, which can effectively increase the number of concurrent connections in the browser, which can bring unexpected improvements to the performance of the Web page, but modern browsers seem to be more willing to treat two different versions of the protocol in an equal way. Newer browsers have changed the concurrency of the two types of protocols. And for the client status of the browser to maintain multiple links for resource consumption is huge, and too many domain names will increase the cost of DNS resolution, so the more concurrent connections open, and does not necessarily achieve the purpose of improving performance, so how many domains most suitable? Yahoo's front-end engineers gave an answer: 2 is the best, the data how to get it I am not very clear, but the result is very simple and easy to use, remember it.



I'm going to talk about how to solve the JS blocking page loading problem, JS will block the UI thread execution, because JS can control the UI display, and the page load rules are to be executed sequentially, so when the JavaScript code encountered the UI line routines first execute it, and this is a lot of programmers do not know or know but ignored , resulting in confusing the code used for presentation and the code used to process logic when writing code, the consequence of which is to make the JS code more congested, so Yahoo's front-end team proposes a front-end optimization rule: Place the JS script at the end of the HTML document, which effectively avoids the UI of blocking. But this method is too simple, not conducive to our site for more in-depth optimization. In order to do in-depth, we need to further analysis, first we know that the JS script is divided into two categories of the occurrence of the script is written on the page, a class of JS external files, inline script optimization is relatively simple, is to try to write less code on the page, even if you want to write code is mainly control page loading UI display code, not necessary code is placed in the external JS file, JS external file optimization is more complex, in order to streamline the inline script, we have to put a lot of JS code in the external file, earlier I will try to combine all the external JS files into a JS file, But now I find that a complex external script is likely to make the page's blocking situation more serious, so the external script to be divided into presentation scripts and logical script according to its function, but in fact the presentation code and logic code is difficult to separate, There's actually a simpler standard that lets us split the code: dividing all the external code into UI initialization code and other code, the UI initialization code is the code that executes when the page loads, and now we just have to figure out what code to do when the page loads, and that's a lot easier.



In addition, I mentioned above I encountered the page was JS blocking the situation, sometimes I would like to debug JS code will always wait for the browser to determine the invalid JS load failure, then how I judge the browser has been judged external JS loading invalid? It is easy to see the browser busy indicating the end, the browser's busy instructions as shown in:







Busy instructions (busy indication includes: Browser tab rotation circle, mouse into a funnel mouse, the left side of the browser status bar display is loading a URL and the old version of IE display page loading progress phenomenon) mark the end of the page loading operation, in order to prevent JS Script blocking page load, So what we're going to do is get the load and execution of the JS code that won't be used for the page initialization to be triggered at the end of the browser's busy instruction, in order to do this we need to know what command is triggered when the busy instruction is finished, which is the browser onload event. So we've got those JS scripts that are irrelevant to the page loading in the OnLoad method, and in the OnLoad event I'll use DOM technology, build the script node, set its src to point to the script path that needs to be loaded, and then A srcipt node is added to the head of the HTML document, in order to make sure that this JS is executed after the busy instruction, I use the SetTimeout method to invoke the dynamic load script method to further ensure that the code is executed after the busy instruction is finished, and the practice feels really good.



Understand here I was very happy, think I understand a front-end development of the difficulties, and have a good solution, but when I recall a bit wrong, I often use the jquery definition of the Ready method, the Ready method will be executed after the DOM loaded, And my own plan is executed after onload, code execution far behind jquery's Ready method execution time, this feeling makes me very uncomfortable, second, in page development we will use a lot of third-party library, although I now develop as far as possible only with jquery this a third-party library, But others are not, they will use a lot of third-party libraries, many libraries have a lot of common methods of UI operation, these methods are very useful, often use these libraries will cause our own Write control UI JS code often rely on them, then split UI control script and other scripts can not be discussed. In short, web front-end development is now too dependent on third-party libraries, even if a good front-end team, refuse to use a third-party library, all of their own development, when the Web application becomes complex, the common library and business code coupling is difficult to solve, which will also lead to the real separation of the UI display code and logic code.



My plan in fact can not meet the actual production needs, not perfect, so this article does not derive a general rule, it is disappointing, facing the above new problems what should we do? This problem is not solvable, the current technology has its solution, that is, the loading of non-blocking scripts. The core of the non-blocking load scripting technique is that when the JS script is loaded, the loaded JS script does not block the execution of the UI thread and the script that is loaded in a blocking manner.



The following is a technical scenario for a non-blocking load script:



  XHR Eval



As the name implies, the script is read through XHR, which takes effect through eval.



The code is as follows:



varxhrObj =newXMLHttpRequest();xhrObj.onreadystatechange =function(){    if(xhrObj.readyState == 4 && 200 == xhrObj.status){        eval(xhrObj.responseText);    }};xhrObj.open("GET","A.js",true);xhrObj.send("");





Because the XMLHttpRequest itself cannot cross the domain, the method cannot cross the domain.



  XHR Injection



Writing scripts using the dynamic creation of a SCRIPT element may be faster than the previous method in some cases.



The code is as follows:


varxhrObj =newXMLHttpRequest();xhrObj.onreadystatechange =function(){    if(xhrObj.readyState == 4){        varscriptElem = document.createElement("script");        document.getElementsByTagName("head")[0].appendChild(scriptElem);        scriptElem.text = xhrObj.responseText;    }};xhrObj.open("GET","A.js",true);xhrObj.send("");








  Script in Iframe



Because the IFRAME is the most expensive DOM element, this approach is avoided as much as possible, and this method cannot be implemented across domains.



  Script DOM Element



A cross-domain scenario that allows scripts to be read and taken into effect by dynamically inserting script elements.



The code is as follows:


varscriptElem = document.createElement("script");scriptElem.src ="http://anydomain.com/A.js";document.getElementByTagName("head")[0].appendChild(scriptElem);





  Script Defer



Native program. Use the Defer property to prevent script blocking.



The code is as follows:



<script defer src="A.js"></script>





However, many browsers do not support this property.



  document.write Script Tag



Another way to write scripts dynamically, but only in IE is downloaded in parallel.



The code is as follows:


document.write("<script type=‘text/javascript‘ src=‘A.js‘></script>");








Script defer and document.write srcipt tag is not a cross-browser scenario and is not recommended here.
Page nested IFRAME scheme I didn't go into the details because I'm sick of it now. Iframe,iframe is the most expensive element in DOM elements, it means slow, and I recently encountered a production problem is the IFRAME caused, because of the IFRAME cross-domain caused, After the IFRAME cross-domain, the parent form and the subform code will not be able to exchange visits, and the IFRAME is incorrectly written (similar to the cross-site script hijacking) also causes the browser to start the default security mechanism, eventually the user can not use the page, so I also do not recommend the use of IFRAME.
XHR Eval is also the way I'm not going to use it because it uses the eval command, and the use of eval often leaves the hacker with a loophole that destroys your site.



So the best solution is XHR injection and Script DOM element, the two scenarios do not have browser compatibility issues, and the latter can cross-domain, but the choice of cross-domain is also to be cautious, cross-domain scripting also brings an invisible security risk, Anyway, these two scenario usage scenarios can basically include all scenarios where a blocking script is loaded.



  Note: The core technique of a nonblocking load script is to dynamically create a script DOM node.



The advantage of non-blocking script loading is that scripts unrelated to page display do not have to be executed in the OnLoad event, it is perfect to run anywhere.



However, the non-blocking script has a big hidden danger, this is a lot of non-blocking scripting technology will be ignored by programmers, the problem is that the non-blocking script is prone to "variable undefined" problem, the essence of this problem is that the non-blocking script will destroy the JS script load order problem, When a script relies on another script, and the other script does not finish loading, there is a "variable undefined" problem, such as that jquery was not loaded prematurely, so the $ time hint variable is undefined.




So how do we solve this problem, Our idea is to let those who rely on the non-blocking loading script of the JS code to execute after the script is loaded, we need a way to order the unordered script loading, I recommend the two methods are using DOM technology to create a script node, and then add the node to the head of the document, For the script node, there is an onload event under the non-IE browser, which will not be executed until the script is loaded, and there is an onreadystatechange event under IE browser. The DOM node of the script under IE has a readystate attribute, which takes the following values:
1. Uninitialized (uninitialized): object has not been initialized,
2. Loading (Loading): The object is loading data,
3. Loaded (Loaded): Object data loading complete
4. Interactive (interactive): The object can be manipulated, but not fully loaded;
5. Complete: The object has been loaded.



scriptNode.onreadystatechange =function(){    if(scriptNode.readystate ==‘complete‘){// todo......}}








This is done by defining a callback function for DOM loading, and the callback function executes when the DOM is loaded, which solves the problem of code execution order.



Another way to do this is to use settimeout, which is to define a poll, determine if a variable is needed, continue polling if it does not exist, and stop polling if the variable exists, as shown in the code pattern:



The code is as follows:


functionlunxun(){    if("undefined"==typeof(XXXX)){        setTimeout(lunxun,300);    }else{        ftn();    }}lunxun();





The advantage of a nonblocking script is that it does not block the execution of the UI, nor does it affect the execution of other synchronous JS code, but the non-blocking script changes the order in which the scripts are loaded, so be sure to pay more attention to the dependencies between scripts when using non-blocking scripts to ensure that the entire page script executes properly.



In the previous article I repeatedly mentioned JS module loading technology, the popular module loading technology has imported requirejs and made Seajs, using these technologies, we will find that JS file loading is loaded by the module, that is, you define how many JS module page, Then this page has how many JS files, just start using them I am very surprised, according to the front-end optimization principle HTTP request less the better, why advanced module technology will make JS file more, then I analyzed the next they loaded JS request, finally understand that they are using the non-blocking script loading technology , that is, using the script node to load scripts, so it is easy to block JS caused by blocking problems.



In the above example, I use the script node to embed scripts into the head node, which seems to be different from the principle of putting the script at the end of the HTML document, this needs to be improved, the answer is no need to improve, put the script at the end of the document to avoid JS blocking, and we use a non-blocking script , this problem is not solved? So it doesn't matter if the code is placed at the head tag or at the bottom of the HTML document.



Finally, I want to correct a wrong point of view, the total page load time is to measure the page load fast standard? The answer is, it is a standard, but is not the most accurate standard, page synchronization blocking load time is the correct standard to measure page load efficiency, non-blocking script loading may increase the time of the entire page load, but it can reduce the page blocking loading time, and page blocking is the culprit that affects the user experience, The most important focus of page optimization is that what you see is going to load more quickly.



non-blocking scripts can split the download and execution of external scripts, which is the hack technology used by programmers, it is cool, but it will cause the complexity of the program and readability, so it should be the technology of the Web front-end architect, and we should use it carefully in daily development.



Explore true nonblocking loading JavaScript scripting technology, we will find a lot of unexpected secrets (reproduced)


Related Article

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.