利用Localstorage进行JS缓存

2017-11-10  本文已影响0人  小漠穷秋

目的:

利用localstorage进行关键Js和CSS缓存,节约下载。

知识点:

1.浏览器默认缓存机制
2.Localstorage
3.异步改造为同步

讲解:

1.浏览器默认会对JS进行缓存。使得下一次进入的时候变为304请求。然而,用户重新刷新等操作时,浏览器会清除这些缓存。所以这些缓存是不可控的。
2.Localstorage的大小大约在5M。
3.异步下载要想保证顺序,可以采用递归的方式。

设计框架:

image.png

代码实现:

window.Xhrfactory = function() {
this.init();
}
window.Xhrfactory.prototype = {
init: function() {
this.xhr = this.create();
},
create: function() {
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xhr = new ActiveXObject('Msml2.Xmlhttp'); //IE7及以后版本IE
}
else {
xhr = new ActiveXobject('Microsoft.Xmlhttp');//其他版本IE
}
return xhr;
},
readystate: function(callback) {
this.xhr.onreadystatechange = function(){
if(this.readyState === 4 && this.status === 200) { //this发生了默认绑定,指向了xhr
callback(this.responseText);
console.log(this);
}
}
},
para: function(data) {
var datastr = '';
if(data && Object.prototype.toString.call(data) === "[object object]") { //判断对象是否为对象
for(var i in data) {
for (var i=0;i<length;i++){
datastr += i + '='
data[i] + '&';
}
}
datastr = '?' + datastr;
}
return datastr;
},
get: function(url,data,callback) {
this.readystate(callback);
var newurl = url;
var datastr = this.para(data);
newurl = url + datastr;
this.xhr.open('get',newurl,false);//这里不能使用true 需要使用false来解决异步问题
this.xhr.send();
}
};

var localStorageSign = 'on'; //后台开关控制,防止缓存失效
var resourceVersion = '20171112'; //版本控制

//本地SDK方法
window.mLocalSdk = {//注意相互依赖,需要按顺序加载
resourceJavascriptList: [
{
id:'0',
url:'./src/js/jquery.js',
type:'javascript'
},
{
id:'1',
url:'./src/js/bootstrap.js',
type:'javascript'
},
{
id:'2',
url:'./src/js/test.js',
type:'javascript'
}
],

resourceCssList : [],
noNeedUpdate: (function() {
    return localStorage.getItem('resourceVersion') === resourceVersion;
})(),

isIE: (function(){
    if (!!window.ActiveXObject || "ActiveXObject" in window) //通过能力判断IE
        return true;
    else
        return false;
})(),
//判断是否超过localstorage的阀值
checkHedge: function(){
    var localStorageLength = localStorage.length;
    var localStorageSize = 0;
    for (var i = 0; i < localStorageLength; i++) {
        var key = localStorage.key(i);
        localStorageByte += localStorage.getItem(key).length;
    }
    return localStorageSize;
},

saveSDK: function() {
    try {
        localStorage.setItem("resourceVersion",resourceVersion);
    } catch (Excepition) {
        if (Exception.name == "QuotaExceededError") {
            localStorage.clear();
            localStorage.setItem("resourceVersion",resourceVersion);
        }
        alert('QuotaExceededError');
    }

    for(var i = 0; i< this.resourceJavascriptList.length; i++) {
        var _self = this;//保存this指针
        (function(i){
            var scriptId = _self.resourceJavascriptList[i].id;
            var xhr = new Xhrfactory();
            xhr.get(_self.resourceJavascriptList[i].url,null,function(data){
                try {
                    localStorage.setItem(scriptId,data);
                } catch (Exception) {
                    console.log('Excpetion',Excpetion);
                    if (Exception.name == "QuotaExceededError") {
                        localStorage.clear();
                        localStorage.setItem("resourceVersion",resourceVersion);
                    }
                }
            })
        })(i);
    }
    for(var i = 0; i< this.resourceCssList.length; i++) {
        var _self = this;//保存this指针
        (function(i){
            var cssId = _self.resourceCssList[i].id;
            var xhr = new Xhrfactory();
            xhr.get(_self.resourceCssList[i].url,null,function(data){
                try {
                    localStorage.setItem(cssId,data);
                } catch (Exception) {
                    console.log('Excpetion',Excpetion);
                    if (Exception.name == "QuotaExceededError") {
                        localStorage.clear();
                        localStorage.setItem("resourceVersion",resourceVersion);
                    }
                }
            })
        })(i);
    }
},
startup: function(){
    var _self = this;
    if (localStorageSign === 'on' && !this.isIE && window.localStorage) {
        if (this.noNeedUpdate === true) {//使用本地 则在本地进行内联引入
            return (function() {
                for (var i = 0; i < _self.resourceJavascriptList.length; i++) {
                    var scriptId = _self.resourceJavascriptList[i].id;
                    window.mDomUtils.addJavascriptByInline(scriptId);   
            }
                for (var i = 0; i < _self.resourceCssList.length; i++) {
                    var cssId = _self.resourceCssList[i].id;
                    var cssString = localStorage.getItem(cssId);
                    window.mDomUtils.addCssByInline(cssString);
            }   
            })();           
        }
        else {
            return (function() {
                _self.saveSDK(); //这里会存在异步回调问题 需要确保保存后再进行后面的操作 通过open.false解决
                for (var i = 0; i < _self.resourceJavascriptList.length; i++) {
                    var scriptId = _self.resourceJavascriptList[i].id;
                        window.mDomUtils.addJavascriptByInline(scriptId);   
                }
                for (var i = 0; i < _self.resourceCssList.length; i++) {
                    var cssId = _self.resourceCssList[i].id;
                    var cssString = localStorage.getItem(cssId);
                    window.mDomUtils.addCssByInline(cssString);
                }
            })();
        }
    }
    else {
        return (function() {//不使用本地,则在外链中引入进行下载,这里存在两个异步问题:1.JS没下载完就继续执行其他程序 2.jq和bs无法保证先后依赖顺序下载
            for (var i = 0; i < _self.resourceCssList.length; i++) {
                    window.mDomUtils.addCssByLink(_self.resourceCssList[i]['url']);                 
            }
            window.mDomUtils.addJavascriptByLink(_self.resourceJavascriptList,0);   
        })()
    }
}

}

window.mDomUtils = {
//内联方式 直接写代码
addJavascriptByInline: function(scriptId) {
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
script.id = scriptId;
var heads = document.getElementsByTagName('head');
if(heads.length) {
heads[0].appendChild(script);
}
else {
document.documentElement.appendChild(script);
}
script.innerHTML = localStorage.getItem(scriptId);
},
//外链方式 直接引用 需要同步加载js
addJavascriptByLink: function(list,count) {
/* var script = document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src',url);
script.id = scriptId;
var heads = document.getElementsByTagName('head');
if (heads.length) {
heads[0].appendChild(script);
} else{
document.documentElement.appendChild(script);
}///这种方式会引起js异步加载,无法达到同步效果 不可取
/
var xhr = new Xhrfactory();
xhr.get(url,null,function(data){
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src',url);
script.id = scriptId;
var heads = document.getElementsByTagName('head');
if (heads.length) {
heads[0].appendChild(script);
} else{
document.documentElement.appendChild(script);
}
});//这种方式会引起js加载两次 不可取*/
var head= document.getElementsByTagName('head');
var script= document.createElement('script');
script.type= 'text/javascript';
script.src = list[count].url;
if (head.length) {
head[0].appendChild(script);
} else{
document.documentElement.appendChild(script);
}//最终选择这种方式进行递归调用 借用jquery思想
script.onload = script.onreadystatechange = function() {
if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete" ) {
count++;
if (count < list.length){
window.mDomUtils.addJavascriptByLink(list,count);
}
else {
return true;
}
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
}
};
},

addCssByInline: function(cssString) {
    var link = document.createElement('link');
    link.setAttribute('type','text/css');
    link.setAttribute('rel','stylesheet');
    if(link.stylesheet){
        link.stylesheet.cssText = cssString;
    }
    else {
        var cssText = document.createTextNode(cssString);
        link.appendChild(cssText);
    }
    var heads = document.getElementsByTagName('head');
    if(heads.length) {
        heads[0].appendChild(link);
    }
    else {
        document.documentElement.appendChild(link);
    }
},

addCssByLink: function(url) {
    var link = document.createElement('link');
    link.setAttribute('href',url);
    link.setAttribute('type','text/css');
    link.setAttribute('rel','stylesheet');
    var heads = document.getElementsByTagName('head');
    if(heads.length) {
        heads[0].appendChild(link);
    }
    else {
        document.documentElement.appendChild(link);
    }
}

}

引入方式:

image.png

代码地址:

git clone https://github.com/kingykking/cacheSDK.git

使用效果:

使用前:


image.png

使用后:


image.png

错误记录:

1.没有按照顺序引入。


image.png

2.外链没有按照顺序引入


image.png
image.png
上一篇下一篇

猜你喜欢

热点阅读