Palo mi je na pamet keširanje JS-a u local storage. Gledam malo po netu i vidim da je local storage dosta brži od standardnog keša, pa se mislim da si složim neki loader.
Da li neko koristi ovu tehniku, kakva su iskustva?
P.S.
Local storage je podržan u svim preglednicima osim u opera mini
Da oko 5mb, zavisi od preglednika. Samo mi nemoj reći da imaš 5mb JS koda na sajtu ?
Znači, keširao bi eksterne JS datoteke (jquery, štagod).
Cilj keširanja u local storage bi bio izbjeći blokiranje parsera, i samim time dobiti na brzini učitavanja.
Koliko brži od standarnog keša? Vjerovatno minorno s obzirom na trajanje loada ostalih asseta.
Ionako je najveci problem prvi load kada nista nije kesirano, a kasnije vjerovatno dodje svejedno jel to localstorage ili keš namjenjen toj svrsi.
A ako odes tim smjerom da radis neke svoje varijante keša,radi minorne dobiti na loadu, navuci ces si samo druge probleme kojih trenutno nisi svjestan…koji trenutno mozda i nisu vidljivi zbog nepredvidljivosti daljnjeg razvoja…
Iako logično, i nije baš tako. Složio sam si loader koji kešira JS u localstorage i nakon testiranja mogu reći da je local storage u nekim situacijama i do 4 puta brži od normalnog keša.
Da, slažem se, ali… baš sam danas saznao da cloudfare koristi ovu tehniku u svom rocket loaderu
Ovaj test baš ne odgovara na moje pitanje. Rekoh da je ušteda vjerovatno minorna s obzirom na trajanje loada ostalih asseta. …što znači da možeš imati i 100% brže učitavanje iz localStoragea,a da je to opet zanemariva ušteda spram onoga koliko će u realnosti load trajati zbog slikica i svega ostaloga.
+ uzmeš u obzir da ovakva optimizacija ne utječe nikako na prvi load, koji je ionako najteži
+ uzmeš u obzir da dodatno kompliciraš i možeš narušiti kompatibilnost s razno raznim alatima koji niču svaki dan.
Tako da možda sve skupa nema smisla, možda ima…na tebi je da odvažeš, jer sam najbolje znaš što želiš postići.
Prvi load je uvijek sranje kod svega, pa tako i kod ovoga.
Kad makneš JS iz DOM-a, nema više ništa što bi blokiralo generiranje CSSOM-a. Dodajmo još i asinkrono učitavanje CSS-a i onda to sve skupa se itekako osjeti.
Evo upravo završavam primjer kojeg ću postati ovdje, pa slobodno testirajte.
Pa ajmo reći da je otprilike to to, iako ni sam više nisam siguran da li sam dobio šta s ovim osim problema
localscript.js
(function(w){
'use strict';
var d = w.document,
self = d.currentScript || d.querySelector('script[data-expire]');
d.addEventListener('DOMContentLoaded', function(){
var ls = w.localStorage,
scripts = d.getElementsByTagName('script');
// check if local storage is supported
if (ls) {
var time = Math.floor(new Date().getTime() / 1000),
expire = ls.getItem('ls-expire'),
expire_in = self.getAttribute('data-expire') || 3600 // expire in seconds
// clear if data is expired
if (null === expire || time > expire) {
ls.clear();
ls.setItem('ls-expire', parseInt(time) + parseInt(expire_in));
}
}
// loop through each script tag
[].forEach.call(scripts, function(script){
var code;
// check type
if (script.type != 'text/localscript') return true;
// cache only external javascript
if (script.hasAttribute('data-src')) {
var src = script.getAttribute('data-src');
code = ls ? ls.getItem(src) : null;
// src is not in storage or local storage is not supported
if (null === code) {
var x = new XMLHttpRequest();
// get the code
x.open('GET', src, script.hasAttribute('async'));
// to-do: timeout
x.send();
// check status
if (x.status === 200) {
code = x.responseText;
// is ls supported
if (ls) {
try {
ls.setItem(src, code);
} catch (e) {
// storage is probably full, flush it out
ls.clear();
}
}
}
}
} else {
code = script.innerHTML;
}
try {
new Function(code)();
}
catch (e) {
console.log(e.name, e.message);
}
});
}, false);
})(this);
Ubacite u footer stranice ovako <script src="localscript.js" data-expire="3600"></script>
data-expire atribut označava koliko će skripta biti keširana u sekundama, zadana vrijednost je 3600 ili jedan sat
Evo malo sam se igrao i uz pomoć promise objekta napravio sam da se svi vanjski resursi učitavaju asinkrono, a izvršavaju sinkrono i sad ovo leti. Inicijalni load je puno brži
/* localscript.js */
(function(w){
'use strict';
var d = w.document,
ls = w.localStorage,
self = d.currentScript || d.querySelector('script[data-expire]');
var get = function(scripts) {
var promises = [];
scripts.forEach(function(script){
var promise = new Promise(function(resolve, reject){
// cache only external javascript
if (script.url) {
// get code
var code = ls ? ls.getItem(script.url) : null;
// url is not in storage or local storage is not supported
if (code === null) {
var xhr = new XMLHttpRequest();
xhr.open('get', script.url);
xhr.onload = function(){
// check status
if (xhr.status == 200) {
// if local storage
if (ls) {
try {
ls.setItem(script.url, xhr.response);
} catch(e) {
ls.clear(); // storage is probably full, flush it
}
}
resolve(xhr.response);
} else {
reject(new Error(xhr.responseURL + ' ' + xhr.statusText));
}
};
xhr.send();
} else {
resolve(code);
}
} else {
resolve(script.code);
}
});
// add promise
promises.push(promise);
});
// return promises
return Promise.all(promises);
};
// hook up
d.addEventListener('DOMContentLoaded', function(){
var data = [],
scripts = d.getElementsByTagName('script');
// check if local storage is supported
if (ls) {
var time = Math.floor(new Date().getTime() / 1000),
expire = ls.getItem('ls-expire'),
expire_in = self.getAttribute('data-expire') || 3600; // expire in seconds
// clear if data is expired
if (null === expire || time > expire) {
ls.clear();
ls.setItem('ls-expire', parseInt(time) + parseInt(expire_in));
}
}
// process all script tags
for(var i in scripts) {
if (scripts[i].type == 'text/localscript') {
data.push({
url : scripts[i].getAttribute('data-src') || null,
code : scripts[i].innerHTML || null
});
}
}
// run
get(data).then(function(codes){
for(var i in codes) {
try {
(0, eval)(codes[i]); // execute scripts in global scope
} catch(e) {
console.log(e.name, e.message);
}
}
}).catch(function(error){
console.log(error);
});
}, false);
})(this);