浏览器缓存 storage

1,692 阅读2分钟

cookie,localStorage,sessionStorage和浏览器数据库IndexDB的对比,对浏览器存储进行了通用封装,避免无痕模式下浏览器存储无法使用,导致开发保存数据失败

「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

基础对比

  • cookie
    • 在同源的http请求中携带,在浏览器和服务器间来回传递
    • 数据存储大小一般不能超过4k
    • 设置的cookie过期时间之前一直有效
    • 在所有同源窗口中都是共享的
    • 适用于和服务端的交互,常用于存储身份信息,如authcode
  • localStorage
    • 持久化本地存储,除非主动删除,否则不会过期
    • 存储大小为5M或更大
    • 在所有同源窗口中都是共享的
    • 适用于长期登陆,判断用户是否已登陆;长期保存数据,可与vuex同步数据
  • sessionStorage
    • 同一个会话的页面才能访问,会话结束时会被清除,仅在当前浏览器窗口关闭前有效
    • 存储大小为5M或更大
    • 不在不同的浏览器窗口中共享
    • 适合敏感账号一次性登陆
  • 浏览器数据库 IndexDB
    • 浏览器提供的本地数据库,允许储存大量数据,提供查找接口,还能建立索引
    • 键值对储存,操作异步,支持事务
    • 存储空间大

无痕限制

问题描述:Safari 开启无痕模式后,localStorage 和 sessionStorage 对象本身是存在的,但对其进行 set 操作会报错。无痕模式下 cookie 是可以使用的。

报错信息:QuotaExceededError(code 为 22,存储空间已用完)。推测浏览器把 storage 的内存先清空,然后再设置最大值为 0导致的

解决方案:对 storage 进行一层封装,定义一个 window 的全局变量进行存储,实现如下所示:

// memoryStorage.js 自定义全局存储
function MemoryStorage() {
  this._store = {};
}

MemoryStorage.prototype.setItem = function (key, val) {
  this._store[key] = String(val);
};
MemoryStorage.prototype.getItem = function (key) {
  return this._store.hasOwnProperty(key) ? this._store[key] : null;
};
MemoryStorage.prototype.removeItem = function (key) {
  delete this._store[key];
};
MemoryStorage.prototype.clear = function () {
  this._store = {};
};
export default MemoryStorage;
// sessionStorage.js 默认存储
import MemoryStorage from "./memoryStorage";

let sessionStorage;

// 判断默认存储是否能用
if (navigator.cookieEnabled && window.sessionStorage) {
  sessionStorage = window.sessionStorage;
} else {
  sessionStorage = new MemoryStorage();
}

export default {
  set(key, val) {
    return sessionStorage.setItem(key, JSON.stringify(val));
  },
  get(key) {
    const val = sessionStorage.getItem(key);
    if (val === null) return null;
    try {
      return JSON.parse(val);
    } catch (e) {
      sessionStorage.removeItem(key);
      return null;
    }
  },
  remove(key) {
    return sessionStorage.removeItem(key);
  },
  clear() {
    return sessionStorage.clear();
  },
};

参考文档: