📜 ⬆️ ⬇️

Parallel loading of JavaScript and CSS without blocking page parsing

It is known that following the ideas of the old school, namely, adding links to JS and CSS to the pages, can turn into a long page load time. The browser displays the page as it is downloaded, but stops if it hits a script tag with a link, until the script is loaded and executed. Sites began to use an increasing number of scripts, the initial display of the page takes more and more time, for example, on this page you are reading, 13 scripts, 7 of which are in the head. In addition, some browsers still adhere to restrictions on the simultaneous number of downloads from a single host.

Immediately I propose to accept that all JS files are minimized, and transmitted in a compressed form.

There are several solutions, such as:
- put styles and scripts directly on the page;
- setting the async / defer attributes to the script tag;
- merge all the scripts into one file;
- Mix the links to the scripts at the end of the body;
- place all files on CDN / on different hosts;
- your own version ...
')
These solutions work, each better or worse depending on how the site itself is built, but they have a number of drawbacks, which I will describe below.
There is an interesting technique that solves the problem of a pause before the initial display of the page, and at the same time adds some convenience. I would venture to suggest that this technique is familiar to many, but nevertheless here I did not see any mention of it.

It all started, of course, from the fact that I took up one project, and at some point it seemed to me that the unpretentious page was loading for a long time, and looked at the download schedule, and the results of YSlow. The fire went out for a second in my eyes, but knowing that it could be better, I climbed to look,

Let us analyze the disadvantages of the above methods.

Putting scripts and styles directly into the page

Obviously, this solution is only suitable for small pages, where there are not many style scripts, since in case of a page reload, static data will be reloaded, and caching may not work. The solution is fully justified for small scripts and styles that are vital from the very moment the page is loaded.

Setting the async / defer attributes to the script tag

The specification is here .
The async and defer attributes of the script tag are supported by the following browsers , which may seem insufficient for those who create websites that people can access with outdated browsers, as well as Opera, which is especially important in runet.
Among the shortcomings, it can also be noted that the scripts loaded from the tag with the defer attribute cannot use document.write, since their execution is not synchronized with the page parser.

Gluing Scripts and Styles

There is an interesting note (carefully, English) and a test that show that downloading a single large file can take longer than parallel loading of individual files. However, this technique is not only worthy of mention and life, but it is also extremely shown to be used if different pages of the site use the same set of scripts or styles.

Placing the stylesheet in the head, and the script in the end of the body

It is worth mentioning and using, but in this case, as in the ones described above, there may be unresolved dependencies between scripts until document.ready, and if this is acceptable for jQuery with plugins, then for the option when we load the Facebook API library or VKontakte, and we want to immediately run our script, which will send a request to the API to determine if the user is logged in, promises crutches, or by loading the API library at the top of the page, blocking its display, which is burdened by having to call DNS resolve.

CDN boot

Using a CDN can reduce the load on your own server, but it can both increase and decrease the load time, or it can completely block the script load, as in the case of an attack on a CDN server or blocking a CDN server on a provider or in an enterprise network.

What other solutions are there?

What if you try to load scripts while the page is loading, but do not execute them, and generally hide from the browser that these are scripts until they have finished loading, so as not to block the initial display of the page?

Somewhere in the notes I found HeadJS , but since the first time I stumbled upon it, he seriously mated, and learned to do not only what we need, but much more. Despite the fact that the library is clearly good, and in the minified form it only takes 3KB, I decided to look for alternatives and found as many as 14 similar libraries, a brief and not always true comparison of which can be found in this note, plus load.js and include.js . Skimming through the libraries presented and noting first large (> 3KB), and then those that I did not like with the syntax or principle of operation, I personally chose YepNope.js , which is part of Modernizr . The authors of the library report that the library is neither better nor worse than the others, and performs the same task as the others, and that they also use other loaders in different projects.

So, what and how does the resource loader on the example of YepNope:
<script src='/javascripts/yepnope-min.js'> yepnope('/javascripts/jquery.min.js', '/javascripts/jquery.loadmask.min.js', '/javascripts/jquery.jgrowl_minimized.js']) </script> 

Execution of the loaded scripts goes in the specified order.

Further in the initialization block:
 yepnope({ load: ['//connect.facebook.net/ru_RU/all.js', '/javascripts/facebook_auth_callback.js'], complete: function(){ FB.init({appId: '273684999999999', xfbml: true, cookie: true, oauth: true}) FB.Event.subscribe('auth.statusChange', facebook_auth) } }) 

So, we get all the desired buns, such as parallel loading, certainty of the execution time of the script, dependencies, callbacks on readiness.

Example of loading styles:
 yepnope(['/stylesheets/jquery.loadmask.css', '/stylesheets/jquery.jgrowl.css']) 

YepNope and other downloaders also have a lot of additional features, the description of which in this topic is not appropriate, but with which it is nice to meet, and everyone has to choose something for himself.

The authors of the scripts can not come to a single principle of operation and API interface, and continue to create all new downloads. In this regard, the author of HeadJS offers to build support for the boot order in the specifications, and the author of $ script.js supports it in this, but until it goes through the specifications and will work the same in all browsers, we will have to use the loaders.

What is the final recipe?
- embed in the head of the page script, pointing to the loader;
- embed an inline script that uses the loader to load other scripts and styles;
- combine scripts and styles that are used only together in one to minimize the number of HTTP requests;
- minimize scripts and styles;
- make sure that the server is packing the transmitted data with gzip;
- make sure that the server is caching correctly;
- carefully and thoughtfully use third-party CDN and additional hosts.

When writing a topic, I looked at the following materials recommended for reading:
[one]. Event sequencing and javascript synchronization
[2]. Simple script loading with yepnope.js
[3]. Description yepnope.js
[four]. Description $ script.js

UPD.
from sHinE Another table-comparison of various boot loaders, with a more complete list.
by S2nek Russian translation of the description of YepNope.

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


All Articles