⬆️ ⬇️

"Accelerate" the opening of a heavy site

The other day it took to speed up the opening of the site. The problem was that only JS-files, even compiled into one and compressed by obfuscation, weighed over 500kB, and yet there is a css also quite large.

In this regard, users who have files cached (for example, a new user or version has changed after the build) had to wait with a slow Internet for a rather long time, looking at the white screen.



And the files need to be downloaded before working with the site, because One big JS-file is a client engine responsible for loading the necessary pages (js pages, template and data), rendering and much more.

In the end, I decided to write a mini-script that will upload files.

In the end, there was another page that showed the progress of downloading all files. In my opinion, this is better than looking at the white screen and wondering what to expect.



The method works on IE9 (with the nuances of course ), IE10 and higher - perfectly, as well as on all major browsers Chrome, Firefox, Opera, Safari.



Styles
.progress-bar { margin: 200px auto; top : -4px; display: none; width : 400px; border: 1px solid gray; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; } .progress-bar div { height : 16px; width : 0; background: lightgray; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; } .progress-bar-text { text-align: center; margin-top: 200px; } 




')

The simplest layout:

 <body> <div class="progress-bar"> <div id="progressBar"></div> </div> <div id="loadingPanel" class="progress-bar-text"> ...  ... </div> </body> 




Since jQuery will still be used in the project, for my script I also decided to connect it, though it was a little reassembled (I threw out most of the functions).



The list of what needs to be loaded will be stored in the variable fileList.

 var progressWidth = 0, fileList = [ {type : 'style', url : '/css/bundle.css'}, {type : 'script', url : '/js/bundle.js'} ]; 




The function that starts the file upload will, upon completion, call a callback passed to it.

 function loadFiles(callback) { if (loaded) { //     window.console && console.error('Already loaded.'); return; } loaded = true; var len = fileList.length, count = len; var _afterAll = function() { if (--count == 0) { if (typeof callback == 'function') { setTimeout(callback, 10); } } }; for(var i = 0; i < len; i++) { loadFile(fileList[i], len, _afterAll); } }; 




In the loop, we run the function responsible for getting the file.

This function will update our progressBar itself.

But how to get download progress? It turns out XMLHttpRequest has long had an onprogress event for downloading a file ( you can read more here ).

But unfortunately, IE9 cannot call onprogress, and by this we check if the new window.XMLHttpRequest () contains an onprogress event. If there is no stub display, with notification, wait, we are loading.

Upon completion of the download, depending on the type of file, we either connect the style (the browser at this time takes the file from the cache, for which we downloaded it), or if it is JavaScript.



 function loadFile(file, len, callback) { var progressBar = $('#progressBar'), loadingPanel = $('#loadingPanel'); file.url += '?' + REVISION; //     ,        $.ajax({ xhr: function () { var xhr = new window.XMLHttpRequest(); if ('onprogress' in xhr) { progressBar.parent().show(); loadingPanel.hide(); var last = 0, max = 100 / len; xhr.addEventListener("progress", function (evt) { if (evt.lengthComputable) { var percentComplete = Math.min((evt.loaded / evt.total) * max, max); if (last < percentComplete) { progressWidth += percentComplete - last; last = percentComplete; progressBar.width(progressWidth + '%'); } } }, false); } return xhr; }, type: 'GET', url: file.url, success: function (data) { if (file.type == 'style') { $('head').append('<link rel="stylesheet" type="text/css" href="' + file.url + '" media="screen" />'); } else if (file.type == 'script') { evalJS(data); } callback(); }, cache : true }); } function evalJS(text) { try { if (window.execScript) { window.execScript(text); } else { eval.call(window, text); } } catch (error) { window.console && console.error(error); } } 




In jQuery, I passed the cache: true property to the ajax method so that the browser does not download files if they are already in the cache, otherwise, by default, jQuery will download the .js files all the time, whether they are in the cache or not .



In general, everything is simple, but as it turned out, in Opera, too, everything is not smooth (at least in version 12) evt.loaded may be several times larger than evt.total .

I did not find any other pitfalls.



Demo

Example Sources

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



All Articles