web 存储机制

# web 存储机制

Web Storage的两个主要目标: 提供一种在cookie之外存储会话数据的途径。 提供一种存储大量可以跨会话存在的数据的机制。

[TOC]

# 一、Storage 类型

# 二、sessionStorage 对象

  • 关闭选项卡后,将删除存储在sessionStorage中的数据。

  • 作用域:同一浏览器+同源文档+同一窗口,才能共享数据,互相读取和覆盖。

    • 例如你在浏览器中打开了两个相同地址的页面A、B,虽然这两个页面的源完全相同,但是他们还是不能共享数据,因为他们是不同窗口中的。但是如果是一个窗口中,有两个同源的iframe元素的话,这两个iframe的 sessionStorage 是可以互通的。

# 三、globalStorage 对象

# 四、localStorage 对象

  • 如果使用localStorage,数据将永远存在,除非例如调用localStorage.clear()

  • 作用域:同一浏览器+同源文档,就能共享数据。

# 4.1 API

localStorage 和 sessionStorage 有着统一的API接口。

  1. 获取数据:localStorage.getItem(key,value)
  2. 设置数据:localStorage.setItem(key,value)
  3. 删除数据:localStorage.removeItem(key)
  4. 清空所有数据:localStorage.clear()
  5. 获取本地存储数据数量:localStorage.length

# 五、storage 事件

# 六、其他

# 6.1 cookies,session, sessionStroage和localStorage的区别

  • cookies,sessionStroage和localStorage是在客户端,session是在服务器端。

    • 服务器端的session机制, session 对象数据保存在服务器上。实现上,服务器和浏览器之间仅需传递session id即可,服务器根据session id找到对应用户的session对象。
    • 会话数据仅在一段时间内有效,这个时间就是server端设置的session有效期。
    • 服务器session存储数据安全一些,一般存放用户信息,浏览器只适合存储一般数据。
  • cookies,sessionStroage和localStorage三者的区别

    特性 Cookie localStorage sessionStorage
    数据的生命期 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 除非被清除,否则永久保存 仅在当前会话下有效,关闭页面或浏览器后被清除,刷新不会被清除
    存放数据大小 4K左右 一般为5MB 👈

| 与服务器端通信 | 每次都会携带在HTTP请求头中,如果使用cookie保存过多数据会带来性能问题 | 仅在客户端(即浏览器)中保存,不参与和服务器的通信 | 👈 | - Web storage 支持事件通知机制,可以将数据更新的通知发送给监听者。

```js
window.addEventListener("storage", function (e) {
    alert(e.newValue);
});
```
# 应用场景

有了对上面这些差别的直观理解,我们就可以讨论三者的应用场景了。

因为考虑到每个 HTTP 请求都会带着 Cookie 的信息,所以 Cookie 当然是能精简就精简啦,比较常用的一个应用场景就是判断用户是否登录。针对登录过的用户,服务器端会在他登录时往 Cookie 中插入一段加密过的唯一辨识单一用户的辨识码,下次只要读取这个值就可以判断当前用户是否登录啦。曾经还使用 Cookie 来保存用户在电商网站的购物车信息,如今有了 localStorage,似乎在这个方面也可以给 Cookie 放个假了~

而另一方面 localStorage 接替了 Cookie 管理购物车的工作,同时也能胜任其他一些工作。比如HTML5游戏通常会产生一些本地数据,localStorage 也是非常适用的。如果遇到一些内容特别多的表单,为了优化用户体验,我们可能要把表单页面拆分成多个子页面,然后按步骤引导用户填写。这时候 sessionStorage 的作用就发挥出来了。

# 安全性的考虑

需要注意的是,不是什么数据都适合放在 Cookie、localStorage 和 sessionStorage 中的。使用它们的时候,需要时刻注意是否有代码存在 XSS 注入的风险。因为只要打开控制台,你就随意修改它们的值,也就是说如果你的网站中有 XSS 的风险,它们就能对你的 localStorage 肆意妄为。所以千万不要用它们存储你系统中的敏感数据。

  • Web Storage的好处

    1. 减少网络流量

      • 一旦数据保存在本地后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数据在浏览器和服务器间不必要地来回传递。
    2. 快速显示数据

      • 性能好,从本地读数据比通过网络从服务器获得数据快得多,本地数据可以即时获得。再加上网页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示。
    3. 临时存储

      • 很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便。

# 6.2 IndexDB

参考教程:

浏览器数据库 IndexedDB 入门教程 (opens new window)

新一代的前端存储方案--indexedDB (opens new window)

IndexDB 的麻瓜式介绍与异步封装 (opens new window)

  • 一个运行在浏览器上的非关系型数据库,理论上没有存储上限;可以存储字符串,还可以储存二进制数据。
// 打开数据库
var request = window.indexedDB.open('test', 1);
var db;
request.onerror = function (event) {
    console.log('数据库打开报错');
};
request.onsuccess = function (event) {
    db = request.result;
    console.log('数据库打开成功');
};
// 当你创建一个新的数据库或者增加已存在的数据库的版本号(当打开数据库时,指定一个比之前更大的版本号), onupgradeneeded 事件会被触发
request.onupgradeneeded = function (event) {
    db = event.target.result;
    var objectStore;
    if (!db.objectStoreNames.contains('person')) {
        objectStore = db.createObjectStore('person', { keyPath: 'id' });
        objectStore.createIndex('name', 'name', { unique: false });	// 建立索引,方便找东西
        objectStore.createIndex('email', 'email', { unique: true });
    }
}

// 新增数据
// add() 保存的主键已存在,则保存失败
// put() 保存的主键已存在,则修改对象

function add() {
  var request = db.transaction(['person'], 'readwrite')
    .objectStore('person')
    .put({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });

  request.onsuccess = function (event) {
    console.log('数据写入成功');
  };

  request.onerror = function (event) {
    console.log('数据写入失败');
  }
}

// 读取数据
function read() {
   var transaction = db.transaction(['person']);
   var objectStore = transaction.objectStore('person');
   var request = objectStore.get(1);	// 参数是主键的值

   request.onerror = function(event) {
     console.log('事务失败');
   };

   request.onsuccess = function( event) {
      if (request.result) {
        console.log("读取的数据",request.result)
      } else {
        console.log('未获得数据记录');
      }
   };
}

read();

// 遍历数据
function readAll() {
  var objectStore = db.transaction('person').objectStore('person');

   objectStore.openCursor().onsuccess = function (event) {
     var cursor = event.target.result;

     if (cursor) {
       console.log("遍历的数据",cursor.value)
       cursor.continue();
    } else {
      console.log('没有更多数据了!');
    }
  };
}

readAll();

// 更新数据
function update() {
  var request = db.transaction(['person'], 'readwrite')
    .objectStore('person')
    .put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });

  request.onsuccess = function (event) {
    console.log('数据更新成功');
  };

  request.onerror = function (event) {
    console.log('数据更新失败');
  }
}

update();

// 删除数据
function remove() {
  var request = db.transaction(['person'], 'readwrite')
    .objectStore('person')
    .delete(1);

  request.onsuccess = function (event) {
    console.log('数据删除成功');
  };
}

remove();
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107