📜 ⬆️ ⬇️

Saving JS and CSS resources in the browser's local storage

The question of whether to keep javascript and css resources of a web page in the browser's LocalStorage or to allow it to work out caching itself does not have a definite answer. There are pros and cons. From my point of view, the main plus - download speed - outweighs the rest. This is very well felt by users of EDGE and 3G.

For fans of the standard browser cache, proudly pointing to the word “Cached” in Developer Tools, I advise you to open Fiddler and see that for every cached resource, a 304 HTTP response is still sent. Then I advise you to go to something like pingdom.com and see that the actual transfer of data in the entire execution time of the request takes interest. That is, the sense in absolute terms of such caching - the cat wept, especially if the files are small.

The proposed storage scheme for resources in LocalStorage is quite simple.
')
First of all, tracking of changes in files is implemented; for this, the time of the last change of the file as its "version" is used. When it changes, the resource is reloaded into local storage.

The resource is linked as follows:

<script type="text/javascript"> <?php include("ls.js"); ?> requireResource( 'mobile.css', 'css', '<?php echo filemtime(__DIR__ . "/css/mobile.css") ?>', '<?php echo "/css/mobile.css?" . filemtime(__DIR__ . "/css/mobile.css") ?>'); </script> 

The requireResource function is passed the name of the resource (under this name it will go to the local storage), the type, version and url of the resource. The ls.js code logic is simple - if the resource is in the repository and its version matches the specified one, it is inline. If not, it is loaded again, placed in the repository, and inline into the HTML code.

 function _cacheResource(name, t, version, url) { var xmlhttp = new XMLHttpRequest(); // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { if (xmlhttp.status == 200) { localStorage.setItem(name, JSON.stringify({ content: xmlhttp.responseText, type: t, version: version })); } else { console.warn('error loading '+url); } } } xmlhttp.open("GET", url, true); xmlhttp.send(); } function _loadResource(url, type, name, version, callback) { if (type == "js") { document.write('<script id="' + name + '" src="', url, '"><\/script>\n'); } else if (type == "css") { document.write('<link id="' + name + '" rel="stylesheet" href="', url, '" />\n'); } var s = document.getElementById(name); if (s.readyState) { //IE s.onreadystatechange = function() { if (s.readyState == "loaded" || s.readyState == "complete") { s.onreadystatechange = null; _cacheResource(name, type, version, url); if (callback) callback(); } }; } else { //Others s.onload = function() { _cacheResource(name, type, version, url); if (callback) callback(); }; } } function _injectResource(content, url, name, version, callback) { var c = JSON.parse(content); // cached version is not the request version, clear the cache, this will trigger a reload next time if (c.version != version) { localStorage.removeItem(name); _loadResource(url, c.type, name, version, callback); return; } if (c.type == "js") { var s = document.createElement('script'); s.type = "text/javascript"; } else if (c.type == "css") { var s = document.createElement('style'); s.type = "text/css"; } var scriptContent = document.createTextNode(c.content); s.appendChild(scriptContent); document.getElementsByTagName("head")[0].appendChild(s); if (callback) callback(); } function requireResource(name, type, version, url, callback) { var c = localStorage.getItem(name); if (c == null) { _loadResource(url, type, name, version, callback); } else { _injectResource(c, url, name, version, callback); } } 

There is a choice how to inline code - or through document.write (); or by inserting an element into the DOM. In the first case, we get a copy of how the resource was picked up by the page itself. The second, in turn, is logically more correct, but there are downsides - js code is not executed, for example. It is necessary to carry out initialization in manual mode - which is easy, but you need to remember this.

Another point - the order of loading resources. If a certain order is needed, it must be provided for - either by arranging the resources in this order in one file, or by synchronous loading.

This example uses 2 types of resources - js and css. In principle, you can expand on everything that can be serialized into the browser's local storage.

The result is obvious - my css and js files no longer appear in the Browser Development Tools and Fiddler (if they are not updated on the server). The site opens significantly faster. The process of js and css debugging on production is not very difficult. And on the development machine, all js and css files are loaded separately for ease of operation.

It should be borne in mind that the means of measuring the speed and performance of a site like Google Pagespeed do not understand such self-made caching and will not show a performance boost.

The basis of js code is taken from GitHub and improved.

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


All Articles