📜 ⬆️ ⬇️

Asynchronous loading of javascript files. Acceleration and optimization of the process, increasing productivity

We continue the cycle of articles on building sites (web applications), focusing on the maximum use of AJAX technology. Often, when sites and applications that use AHAH are used, it is required to load script files that are not previously used on the site’s pages along with loaded HTML content. One of the aspects of processing the content being reloaded by AJAX is the selection of the script files from the resulting content, followed by their application to the current document (DOM). Fortunately, at the moment almost all the major libraries are able to do it. However, if you dig deeper into the implementation of the processing process of the loaded scripts, the current situation is completely “not bright”. Not all well-known libraries can do this well, much less optimally. Let's look at this process from the inside, analyze existing problems and find out ways to solve them.

For ease of understanding, we will consider a complex example in which, using AJAX, we will load an additional page into the start page, in which, in turn, there are links to script files.

So, in the start page we will load an additional page test1.html, the text of which is shown below.
< html >
< head >
< script type ="text/javascript" src ="test1.js" ></ script >
<script type= "text/javascript" src= "test2.js" > </ script >
< link type ="text/css" rel ="stylesheet" href ="test.css" />
</ head >
< body >
Hello Bingo!
</ body >
</ html >


Download this page using the well-known jQuery library. The jquery1.html start page text is shown below.
< html >
< head >
< script type ="text/javascript" src ="test1.js" ></ script >
<script type= "text/javascript" src= "jquery-1.2.6.js" ></script>
</head>
<body>
<div id= "content1" ></div>
<div id= "content2" ></div>
<script type= "text/javascript" >
$( function (){
$( '#content1' ).load( 'test1.html' )
$( '#content2' ).load( 'test1.html' )
})
</ script >
</ body >
</ html >



To identify problem areas, load the additional page twice into the content1 and content2 blocks, respectively.
')
The firebug console will show us something like

GET test1.html
GET test1.html
GET test1.js? _ = 1239115065471
GET test2.js? _ = 1239115067323
GET test1.js? _ = 1239115068456
GET test2.js? _ = 1239115069347

As you can see, jQuery, with asynchronous loading of content, adds a prefix of _ = 1239115067323 to the addresses of scripts, so that the script is not cached. Thus, when using jQuery, the browser each time will load the same script on different pages again, on a full cycle, without using the cache. The question is “Why?” The probability that for different pages the same script (with the same address) will be different almost = 0. Accordingly, the process of loading the scripts is clearly not well thought out. However, the purpose of the article is not to criticize the work of jQuery. Similarly, with other libraries. The purpose of the article is to understand the principles and ways of the possible optimization of the process of asynchronous loading of scripts.

In this article, for simpler presentation and understanding of the material, regarding ways and options for optimizing asynchronous script loading, the implementation of the optimization of the process in the Fullajax library will be described.

Optimization step 1 - Start at the pier


Why download what is already in memory and loaded on the start page?

Note that test1.js script is already connected on the start page, i.e. he is already in memory. Accordingly, it is quite easy to get its contents without any additional data download from the server. Thus, the first thing we do is check whether the script is already loaded (connected) to the page in a standard way? If yes, just get its content and execute it. By performing the specified simple operation, relative to our example, we immediately get rid of 2 extra requests to the server.

Optimization Step 2 - Repetition Mother of Torment


Why re-download what has already been uploaded once?

Let's look again at the firebug console. Pay attention to the order and the number of script downloads using jQuery. The script test1.js and test2.js are loaded twice each! We figured out the test1.js script in the previous step. Now we optimize loading of the second script. The test2.js script is enough to load once (for the first time), put its content "by the cheek" (into the software cache) and all subsequent times get it from there, and not from the server. Thus, with respect to our example, we get rid of one extra script load and, accordingly, an extra server request.

In sum, on a simple example, we have a “concrete” optimization, namely, as a result, only 1 request from 4 initial requests. The above optimization steps work in the default Fullajax library. Those. By default, the start page scripts are not reloaded, and also all new scripts are loaded only once.

fullajax.ru/temp/asyncjs/fullajax1.html

The implementation of optimization step # 1 is still more or less transparent - we find all the scripts in the head block and get their contents. The implementation of optimization step # 2 required additional synchronization between parallel asynchronous page requests from the server. Often there is a situation when the second parallel request began before the first one ended, i.e. The second request started before we got the script text. Accordingly, it is necessary to ensure synchronization between threads so that at the end of the script download from the first thread, the second thread will immediately recognize this. In general, this is a more in-depth topic ...

Fortunately and surprisingly, the optimization options are incomplete. We can still remove unnecessary "movement."

Optimization step 3 - Re-initialization enemy optimization


Why execute (initialize) again what has already been executed (initialized)?

In the previous optimization steps, getting rid of re-loading scripts, we still continue to re-execute the same scripts. Let's look inside the test1.js and test2.js scripts.

Script test1.js
var a = Math.random();

Script test2.js
function test(){
alert( 'Hello' );
}

Regarding the test1.js script, it is important for us to execute it every time, with each new boot, since the value of the variable a will depend on it. Here we can not do anything, accept this.

Regarding the test2.js script, its repeated execution carries no payload. The test function has already been defined once, and with each subsequent download of this script, this function simply overrides itself. Accordingly, we can safely not re-execute this script. Thus, we will save processor time and possibly memory. However, we do not have standard tools at hand that allow the script to be executed only once (hello to the HTML standard). To do this, you must either change the internal structure of the script, so that a check on the previous execution is carried out, or give the asynchronous script loading engine (library) with an appropriate algorithm.
Consider the implementation of this optimization step in Fullajax. In order to carry out a one-time execution of some scripts, it is necessary and sufficient to just add the "magic" attribute ax: repeat = '0' to them .
< script type ="text/javascript" ax:repeat ="0" src ="test2.js" ></ script >
And that's all :). Further, the script loading algorithm will automatically optimize the execution of such marked scripts, i.e. such scripts will be executed only once. The determination of the need or absence of the need to re-execute (initialize) scripts is made by the developer himself. Analyze your scripts! If there is no need to re-execute them, feel free to tag them with the appropriate attribute. In some cases, the re-execution of individual scripts even causes errors in the site (web application). Such an example is the many famous calendar script ( Zapatec Calendar ). If repeatedly, when AJAX loads content, execute the calendar.js script from the set of scripts, the calendar stops working and gives errors.

Not tired? I was already a bit “tired” of describing ... imagine how much the above described was programmed :).

And this is not all possible ways of optimization, there is also something that can be optimized during asynchronous loading of scripts.

Optimization Step 4 - Parallels Songs Sang


Let's consider the case when there are several scripts in the loaded page. For example
< html >
< head >
< script type ="text/javascript" src ="test1.js?1" ></ script >
<script type= "text/javascript" src= "test1.js?2" ></script>
<script type= "text/javascript" src= "test1.js?3" ></script>
<script type= "text/javascript" src= "test1.js?4" ></script>
<script type= "text/javascript" src= "test1.js?5" ></script>
<script type= "text/javascript" src= "test1.js?6" ></script>
<script type= "text/javascript" src= "test1.js?7" ></script>
<script type= "text/javascript" src= "test1.js?8" ></script>
<script type= "text/javascript" src= "test1.js?9" ></script>
<script type= "text/javascript" src= "test1.js?10" > </ script >
</ head >
< body >
Hello Bingo!
</ body >
</ html >

jQuery in this case begins to load the first script, then, at the end of the first, it starts loading the second, then at the end of loading the second, the third, and so on. Those. in fact, synchronous sequential loading of scripts is performed.

fullajax.ru/temp/asyncjs/jquery2.html

And it is quite normal! All browsers behave in the same way with standard script loading. Because the execution of the subsequent script may depend on the previous one. Therefore, we must wait for the execution of the first, and then perform the second.
But! "Run" is not at all tantamount to "loading." After all, we can carry out parallel loading of all scripts? .. But we will execute them already sequentially, as they are loaded.
Thus, implementing the above algorithm, we get a real safe asychronic script loading. This optimization algorithm is called - parallel loading algorithm with sequential application .

fullajax.ru/temp/asyncjs/fullajax2.html

With more close to real conditions, we load large script files.

jQuery

fullajax.ru/temp/asyncjs/jquery3.html

Fullajax

fullajax.ru/temp/asyncjs/fullajax3.html

The conclusions are obvious.

The specified algorithm for optimizing the loading of scripts is implemented in the Fullajax library and is used by default.

And a little more optimization - skip ~ perform miracles


Sometimes, when uploading content using AJAX, it becomes necessary to disable the execution of certain scripts, and at the same time to carry out their normal execution with the usual standard load. There is no simple standard way to do this. To implement the specified functionality, it is necessary for the server to determine how content is requested (via AJAX or the standard way), accordingly, add or remove certain scripts from the page content. When using Fullajax, there is a much simpler way - add the “wonderful” attribute to the style ax: skip = '1' . Now the library will skip (ignore) the scripts you have marked accordingly, will not even try to load them.

There are still a lot of other questions regarding the processing of scripts in various libraries. For example: why jQuery first inserts the content, and then executes the scripts, if in the loaded document it is clearly indicated to first run the scripts, and then insert the content. There are also other points that go beyond the scope of this article.

In this article, we have analyzed and analyzed in detail the various bottlenecks that arise during the asynchronous loading of HTML content with scripts, and also considered possible ways to optimize such bottlenecks.

The material of the article is unique, it has never been covered or voiced anywhere before, it is published for the first time. All conclusions and algorithms are derived by the author in the process of developing the Fullajax library .

jQuery I love too :).

UPD: - added tests when loading large script files.

Source: https://habr.com/ru/post/56974/


All Articles