html5本地存储localstorage-mile米乐体育

前几天在老项目中发现有对cookie的操作觉得很奇怪,咨询下来是要缓存一些信息,以避免在url上面传递参数,但没有考虑过cookie会带来什么问题:

① cookie大小限制在4k左右,不适合存业务数据 ② cookie每次随http事务一起发送,浪费带宽

我们是做移动项目的,所以这里真实适合使用的技术是localstorage,localstorage可以说是对cookie的优化,使用它可以方便在客户端存储数据,并且不会随着http传输,但也不是没有问题:

① localstorage大小限制在500万字符左右,各个浏览器不一致 ② localstorage在隐私模式下不可读取 ③ localstorage本质是在读写文件,数据多的话会比较卡(firefox会一次性将数据导入内存,想想就觉得吓人啊) ④ localstorage不能被爬虫爬取,不要用它完全取代url传参

瑕不掩瑜,以上问题皆可避免,所以我们的关注点应该放在如何使用localstorage上,并且是如何正确使用。

基础知识

localstorage存储对象分为两种:

① sessionstrage: session即会话的意思,在这里的session是指用户浏览某个网站时,从进入网站到关闭网站这个时间段,session对象的有效期就只有这么长。

② localstorage: 将数据保存在客户端硬件设备上,不管它是什么,意思就是下次打开计算机时候数据还在。

两者区别就是一个作为临时保存,一个长期保存。

这里来一段简单的代码说明其基本使用:

真实场景

实际工作中对localstorage的使用一般有以下需求:

① 缓存一般信息,如搜索页的出发城市,达到城市,非实时定位信息

② 缓存城市列表数据,这个数据往往比较大

③ 每条缓存信息需要可追踪,比如服务器通知城市数据更新,这个时候在最近一次访问的时候要自动设置过期

④ 每条信息具有过期日期状态,在过期外时间需要由服务器拉取数据

⑤ ……

define([], function () {    var storage = _.inherit({     //默认属性     propertys: function () {        //代理对象,默认为localstorage       this.sproxy = window.localstorage;        //60 * 60 * 24 * 30 * 1000 ms ==30天       this.defaultlifetime = 2592000000;        //本地缓存用以存放所有localstorage键值与过期日期的映射       this.keycache = 'system_key_timeout_map';        //当缓存容量已满,每次删除的缓存数       this.removenum = 5;      },      assert: function () {       if (this.sproxy === null) {         throw 'not override sproxy property';       }     },      initialize: function (opts) {       this.propertys();       this.assert();     },      /*     新增localstorage     数据格式包括唯一键值,json字符串,过期日期,存入日期     sign 为格式化后的请求参数,用于同一请求不同参数时候返回新数据,比如列表为北京的城市,后切换为上海,会判断tag不同而更新缓存数据,tag相当于签名     每一键值只会缓存一条信息     */     set: function (key, value, timeout, sign) {       var _d = new date();       //存入日期       var indate = _d.gettime();        //最终保存的数据       var entity = null;        if (!timeout) {         _d.settime(_d.gettime()   this.defaultlifetime);         timeout = _d.gettime();       }        //       this.setkeycache(key, timeout);       entity = this.buildstorageobj(value, indate, timeout, sign);        try {         this.sproxy.setitem(key, json.stringify(entity));         return true;       } catch (e) {         //localstorage写满时,全清掉         if (e.name == 'quotaexceedederror') {           //            this.sproxy.clear();           //localstorage写满时,选择离过期时间最近的数据删除,这样也会有些影响,但是感觉比全清除好些,如果缓存过多,此过程比较耗时,100ms以内           if (!this.removelastcache()) throw '本次数据存储量过大';           this.set(key, value, timeout, sign);         }         console && console.log(e);       }       return false;     },      //删除过期缓存     removeoverduecache: function () {       var tmpobj = null, i, len;        var now = new date().gettime();       //取出键值对       var cachestr = this.sproxy.getitem(this.keycache);       var cachemap = [];       var newmap = [];       if (!cachestr) {         return;       }        cachemap = json.parse(cachestr);        for (i = 0, len = cachemap.length; i < len; i  ) {         tmpobj = cachemap[i];         if (tmpobj.timeout < now) {           this.sproxy.removeitem(tmpobj.key);         } else {           newmap.push(tmpobj);         }       }       this.sproxy.setitem(this.keycache, json.stringify(newmap));      },      removelastcache: function () {       var i, len;       var num = this.removenum || 5;        //取出键值对       var cachestr = this.sproxy.getitem(this.keycache);       var cachemap = [];       var delmap = [];        //说明本次存储过大       if (!cachestr) return false;        cachemap.sort(function (a, b) {         return a.timeout - b.timeout;       });        //删除了哪些数据       delmap = cachemap.splice(0, num);       for (i = 0, len = delmap.length; i < len; i  ) {         this.sproxy.removeitem(delmap[i].key);       }        this.sproxy.setitem(this.keycache, json.stringify(cachemap));       return true;     },      setkeycache: function (key, timeout) {       if (!key || !timeout || timeout < new date().gettime()) return;       var i, len, tmpobj;        //获取当前已经缓存的键值字符串       var oldstr = this.sproxy.getitem(this.keycache);       var oldmap = [];       //当前key是否已经存在       var flag = false;       var obj = {};       obj.key = key;       obj.timeout = timeout;        if (oldstr) {         oldmap = json.parse(oldstr);         if (!_.isarray(oldmap)) oldmap = [];       }        for (i = 0, len = oldmap.length; i < len; i  ) {         tmpobj = oldmap[i];         if (tmpobj.key == key) {           oldmap[i] = obj;           flag = true;           break;         }       }       if (!flag) oldmap.push(obj);       //最后将新数组放到缓存中       this.sproxy.setitem(this.keycache, json.stringify(oldmap));      },      buildstorageobj: function (value, indate, timeout, sign) {       var obj = {         value: value,         timeout: timeout,         sign: sign,         indate: indate       };       return obj;     },      get: function (key, sign) {       var result, now = new date().gettime();       try {         result = this.sproxy.getitem(key);         if (!result) return null;         result = json.parse(result);          //数据过期         if (result.timeout < now) return null;          //需要验证签名         if (sign) {           if (sign === result.sign)             return result.value;           return null;         } else {           return result.value;         }        } catch (e) {         console && console.log(e);       }       return null;     },      //获取签名     getsign: function (key) {       var result, sign = null;       try {         result = this.sproxy.getitem(key);         if (result) {           result = json.parse(result);           sign = result && result.sign         }       } catch (e) {         console && console.log(e);       }       return sign;     },      remove: function (key) {       return this.sproxy.removeitem(key);     },      clear: function () {       this.sproxy.clear();     }   });    storage.getinstance = function () {     if (this.instance) {       return this.instance;     } else {       return this.instance = new this();     }   };    return storage;  });

这段代码包含了localstorage的基本操作,并且对以上问题做了处理,而真实的使用还要再抽象:

define(['abstractstorage'], function (abstractstorage) {    var store = _.inherit({     //默认属性     propertys: function () {        //每个对象一定要具有存储键,并且不能重复       this.key = null;        //默认一条数据的生命周期,s为秒,m为分,d为天       this.lifetime = '30m';        //默认返回数据       //      this.defaultdata = null;        //代理对象,localstorage对象       this.sproxy = new abstractstorage();      },      setoption: function (options) {       _.extend(this, options);     },      assert: function () {       if (this.key === null) {         throw 'not override key property';       }       if (this.sproxy === null) {         throw 'not override sproxy property';       }     },      initialize: function (opts) {       this.propertys();       this.setoption(opts);       this.assert();     },      _getlifetime: function () {       var timeout = 0;       var str = this.lifetime;       var unit = str.charat(str.length - 1);       var num = str.substring(0, str.length - 1);       var map = {         d: 86400,         h: 3600,         m: 60,         s: 1       };       if (typeof unit == 'string') {         unit = unit.touppercase();       }       timeout = num;       if (unit) timeout = map[unit];        //单位为毫秒       return num * timeout * 1000 ;     },      //缓存数据     set: function (value, sign) {       //获取过期时间       var timeout = new date();       timeout.settime(timeout.gettime()   this._getlifetime());       this.sproxy.set(this.key, value, timeout.gettime(), sign);     },      //设置单个属性     setattr: function (name, value, sign) {       var key, obj;       if (_.isobject(name)) {         for (key in name) {           if (name.hasownproperty(key)) this.setattr(k, name[k], value);         }         return;       }        if (!sign) sign = this.getsign();        //获取当前对象       obj = this.get(sign) || {};       if (!obj) return;       obj[name] = value;       this.set(obj, sign);      },      getsign: function () {       return this.sproxy.getsign(this.key);     },      remove: function () {       this.sproxy.remove(this.key);     },      removeattr: function (attrname) {       var obj = this.get() || {};       if (obj[attrname]) {         delete obj[attrname];       }       this.set(obj);     },      get: function (sign) {       var result = [], isempty = true, a;       var obj = this.sproxy.get(this.key, sign);       var type = typeof obj;       var o = { 'string': true, 'number': true, 'boolean': true };       if (o[type]) return obj;        if (_.isarray(obj)) {         for (var i = 0, len = obj.length; i < len; i  ) {           result[i] = obj[i];         }       } else if (_.isobject(obj)) {         result = obj;       }        for (a in result) {         isempty = false;         break;       }       return !isempty ? result : null;     },      getattr: function (attrname, tag) {       var obj = this.get(tag);       var attrval = null;       if (obj) {         attrval = obj[attrname];       }       return attrval;     }    });    store.getinstance = function () {     if (this.instance) {       return this.instance;     } else {       return this.instance = new this();     }   };    return store; });

我们真实使用的时候是使用store这个类操作localstorage,代码结束简单测试:

存储完成,以后都不会走请求,于是今天的代码基本结束 ,最后在android hybrid中有一后退按钮,此按钮一旦按下会回到上一个页面,这个时候里面的localstorage可能会读取失效!一个简单不靠谱的mile米乐体育的解决方案是在webapp中加入:

window.onunload = function () { };//适合单页应用,不要问我为什么,我也不知道
localstorage是移动开发必不可少的技术点,需要深入了解,具体业务代码后续会放到git上,有兴趣的朋友可以去了解
展开全文
内容来源于互联网和用户投稿,文章中一旦含有米乐app官网登录的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系米乐app官网登录删除

最新文章

知识分享
这条河堤道路,路面窄到一条中心线都画不出来,各种电动车、三轮车、摩托车、机动车、非机动车往...…
知识分享
导语:为何汽车备用胎和正常轮胎尺寸不一样?老司机:症结主要在这三处汽车的备胎分为三种,一种...…
知识分享
首先,我们需要将油箱里面废弃的机油排出,先拧下油箱底部的螺丝,排出废油,再更换滤清器(注意...…
知识分享
二手车价格通常会因为车漆喷涂范围加大而降低,但并非所有喷过漆的车辆都不能入手,例如处理过划...…
网站地图