利用Localstorage进行JS缓存

目的:

利用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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • 个人博客:https://yeaseonzhang.github.io 花了半个多月的时间,终于又把“JS红宝书”...
    Yeaseon阅读 1,751评论 2 23
  • 数据结构与算法 栈和队列的区别 网络基础 HTTP 无状态怎么理解 可以从REST的角度来理解这个问题。我们知道R...
    笑极阅读 665评论 1 5
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,761评论 2 17
  • Ajax和XMLHttpRequest 我们通常将Ajax等同于XMLHttpRequest,但细究起来它们两个是...
    changxiaonan阅读 2,236评论 0 2
  • 今天重庆转暖了。 阳光刺破了重重的云雾,终于肯灿烂的撒过来。 前几天立春刚过,年后的人群刚散,山底的桃花才刚刚绽开...
    Crust阅读 178评论 0 0