localStorage
作为本地存储来使用的,解决了cookie存储空间不足的问题(cookie中每条cookie的存储空间为4k),localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同。localStorage的存储结构实质是哈希表。
优势
- localStorage拓展了cookie的4K限制
- localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,相比于cookie可以节约带宽,但是这个却是只有在高版本的浏览器中才支持的
局限
- 浏览器的大小不统一,并且在IE8以上的IE版本才支持localStorage这个属性
- 目前所有的浏览器中都会把localStorage的值类型限定为string类型,这个在对我们日常比较常见的JSON对象类型需要一些转换
- localStorage在浏览器的隐私模式下面是不可读取的
- localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
- localStorage不能被爬虫抓取到
使用
localStorage(对象)只支持string类型的存储
- JSON.stringify():将JSON转换成为JSON字符串
- JSON.parse():将JSON字符串转换成为JSON对象
- 是否兼容
1 | if(!window.localStorage) |
- 写入/写入
1
2
3localStorage["a"]=1;
localStorage.a=1;
localStorage.setItem("c",3);
localStorage的使用也是遵循同源策略的,所以不同的网站直接是不能共用相同的localStorage
- 读取
1 | var a=localStorage.a; |
- 删除
清除当前域名下的所有localstorage数据
1
localStorage.clear()
删除某个键值对:
1
localStorage.removeItem("a")
数据共享
- localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据
- sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。
生存期
在数据存储的时效性上,localStorage并不会像cookie那样可以设置数据存活的时限。也就是说,只要用户不主动删除,localStorage存储的数据将会永久存在。
存储位置
对于localStorage数据的存储,是存在于本地的文件系统(客户端硬件设备)中的
例如,对于chrome来说,localStorage数据的存储位置是在:C:\Users{userName}\AppData\Local\Google\Chrome\User Data\Default\Local Storage中
在 setItem 时,可能会达到大小限制,最好加上错误捕捉try/catch
1 | try { |
在ios设备上无法重复setItem()
另外,在iPhone/iPad上有时设置setItem()时会出现诡异的QUOTA_EXCEEDED_ERR错误,这时一般在setItem之前,先removeItem()就ok了
给localStorage设置一个过期时间
1 | function set(key,value){ |
具体方法
- 重写set
- 首先有三个参数 key、value、expired ,分别对应 键、值、过期时间,
- 这个时间如何设置呢?在这个值存入的时候在键(key)的基础上扩展一个字段,如:key+’expires’,而它的值为当前 时间戳 + expired过期时间
1 | set(key, value, expired) { |
- 重写get
- 获取数据时,先判断之前存储的时间有效期,与当前的时间进行对比;
- 但存储时expired为非必须参数,所以默认为当前时间+1,即长期有效;
- 如果存储时有设置过期时间,且在获取的时候发现已经小于当前时间戳,则执行删除操作,并返回空值;
1 | get(key) { |
- 重写remove
1 | remove(key) { |
- 将删除操作放到constructor里面(不取get的时候也可以清除)
localStorage如果不主动清除是一直存在的,也就是会占用存储空间,所以默认会在constructor里清除一次,已经过期的数据。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class storage {
constructor(props) {
this.props = props || {}
this.source = this.props.source || window.localStorage
this.initRun();
}
initRun(){
/*
* set 存储方法
* @ param {String} key 键
* @ param {String} value 值,存储的值可能是数组/对象,不能直接存储,需要转换 JSON.stringify
* @ param {String} expired 过期时间,以分钟为单位
*/
const reg = new RegExp("__expires__");
let data = this.source;
let list = Object.keys(data);
if(list.length > 0){
list.map((key,v)=>{
if( !reg.test(key )){
let now = Date.now();
let expires = data[`${key}__expires__`]||Date.now+1;
if (now >= expires ) {
this.remove(key);
};
};
return key;
});
};
}
}
localStorage字符串最大容量是5M,那么我如果存储容量溢出了怎么办?
其实这个5M对于不同浏览器来说也是不确定的,不过大体上是一个5M的范围,溢出了怎么办,肯定会发生错误啊。浏览器会报一个名为“QuotaExceededError”的错误
最后一次溢出的字符串是会存储到最大容量停止还是不会存储?
正常情况下,可能不会存储5M的字符串,但是也不能保证浏览器日积月累的情况下,恰巧用户也没清理过缓存,那么当最后容量接近5M的时候,我们再存储一个字符串进去的时候会发生错误,发生错误的字符串是存了一半?还是压根就没存呢?答案是—没存。下面是我写的一个demo,最后发现报错的时候刷新浏览器,localStorage的当前容量为发生变化。
所以超过限制大小的时候,浏览器会:
- 不存储数据,也不会覆盖现有数据
- 引发 QUOTA_EXCEEDED_ERR 异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15(function(){
var safeLocalStorage = function(key, value) {
try{
localStorage.setItem(key,value);
}catch(oException){
if(oException.name == 'QuotaExceededError'){
console.log('已经超出本地存储限定大小!');
// 可进行超出限定大小之后的操作,如下面可以先清除记录,再次保存
localStorage.clear();
localStorage.setItem(key,value);
}
}
}
this.safeLocalStorage = safeLocalStorage;
})();
localStorage一般小于5M,是每个域5M,如果超出限制,可以:(借助postMessage和iframe来实现跨域的数据读取)
- 申请其他域
- 修改ng配置
- 配置postmessage通信往其他域上存取
一般可以利用 indexedDB 存文件类型的数据,localStorage 存业务数据
获得localStorage已使用容量
1 | (function(){ |