Explore the true non-blocking loading JavaScript scripting technology, we'll find a lot of unexpected secrets

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.

Some of the systems I have developed in the development environment often encounter JavaScript blocking page loading, mainly because many of our site's static resources and scripts are independently extracted on a separate static resource server. While the local development environment simulation of the static resource service environment is often very unstable (often down), sometimes some new scripts are not updated to the development environment, so some JS script files can not be obtained correctly, these problems cause the page load time these JS script will block the page loading, At this time 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, forcing the browser to close the request, you will find in the browser console many scripts can not be found, so you can not set the JS code breakpoint debugging JS in the console, If you wait for JS to load, the time will be wasted, helpless as long as you find those invalid URLs to comment out, hey, the results several times have commented error code submitted to the SVN server, these things are really annoying.

Regardless of the browser, the new version or the old version of the browser, they uphold the single-threaded nature of the browser, this feature seems to be a difficult rule, when we enter a URL in the browser address bar, access to a new page, the speed of the page is controlled by a single thread, This thread is called the UI thread, and the UI thread loads the resources according to the order in which the resources in the page are written (resources refer to CSS files, pictures, and so on), and loads the resources using HTTP requests for resources, like external CSS files. HTML files and pictures and other resources HTTP request processing completed also means that the resource load is finished, but like external JavaScript file is different, its loading process is divided into two steps, the first step and load CSS files and pictures, is to execute an HTTP request to download the external JS file, However, JavaScript does not mean that after the completion of the HTTP operation, 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 page delay. 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 is like multiple threads together to complete a task, if the parallel HTTP connection more, then more HTTP resources can be downloaded at the same time, but the browser provides parallel execution of the HTTP connection is too few, such as the above Firefox two, There are only 4 chrome, so how do you break the limit of the number of connections in your browser? 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 is a bit of a browser clever, is the programmer to discover the characteristics of the browser summed up the technology, it is similar to a hack technology, and hack technology is not standard technology, so it must have its bottleneck area, so this technology will have a degree, the browser limit the number of requests is absolutely not unprovoked, We look at the Baidu page parallel download images of the version of the HTTP protocol is 1.1,http1.1 feature is a long connection, the benefits of long connection is in the page and server frequently interactive time is very efficient, but the browser's page operation is not always a frequent request server, and in order to load static resources and create a lot of long connections, the server will have to maintain large The amount of useless long connection, the pressure to the server is conceivable. In contrast to the http1.0 protocol, it does not use a long connection, but rather a short connection, so earlier versions of the browser would have more connections to the HTTP1.0 protocol than the http1.1 connection, so some websites reduced the HTTP protocol version provided by the static resource server to 1.0, which would effectively increase the number of concurrent connections to the browser, which A way to improve the performance of Web pages, but modern browsers seem to be more willing to treat two different versions of the protocol, the new version of the browser some of the two types of protocols to the same number of concurrent. 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 is that the blocking of the JS code is more serious, so the Yahoo front team proposes a front-end optimization rule: Place the JS script at the end of the HTML document, This will effectively prevent the UI from 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 of all we know that 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 to control the page loading UI display code, no necessary code 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 large number of JS code in the external file, I tried to merge all the external JS files into a single JS file earlier, but now I find that a complex external script is likely to make the page's blocking situation more serious, so the external script will be divided into the presentation script 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 aren't related to page loading executed in the OnLoad method, and in the OnLoad event I'll use DOM technology to build the script node, set its src to point to the script path that needs to be loaded, Then add this srcipt node to the head of the HTML document, in order to fully ensure that this JS at the end of the busy instructions to execute, I use the SetTimeout method to invoke the dynamic load script method, further ensure that the code is executed after the end of the busy instruction, the practice of feeling the effect is 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:

?
123456789 var xhrObj = new XMLHttpRequest();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:

?
12345678910 var xhrObj = new XMLHttpRequest();xhrObj.onreadystatechange = function(){    if(xhrObj.readyState == 4){        var scriptElem = 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:

?
123 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:

?
1 <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:

?
1 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 rely on the non-blocking loading of the script's JS code to execute after the script is loaded, we need a way to order the unordered script loading, the above I recommend the two methods are using DOM technology to create a script node, Then add the node to the head of the document, for the script node, there is an onload event in the non-IE browser, the event will be executed after the script has been loaded, ie browser has the onreadystatechange event, The DOM node of the script under IE has a readystate property, and it has the following values:
1.uninitialized (uninitialized): object has not been initialized;
2.loading (Loading): The object is loading data;
3.loaded (finished Loading): Object Data loading complete
4.interactive (Interactive): Can manipulate objects, but not fully loaded;
5.complete (completed): The object has been loaded.
The specific usage is as follows:

?
123 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:

?
12345678 function lunxun(){    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 the true non-blocking loading JavaScript scripting technology, we'll find a lot of unexpected secrets

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.