浏览器数据存储方式

浏览器数据存储方式

常用的前端数据存储方法笼统来说有 3 种:

  • local/session storage
  • cookies
  • indexeddb

3 种方法各有各的优点和使用范围。

local/session storage

local/session storage 保存的格式都为键值对,并且用法都是差不多,如下:

const userid = 'u12345';
const user = {
    
    
  name: 'name',
  age: 18,
  status: 'active',
};

document.querySelector('#store').addEventListener('click', () => {
    
    
  sessionStorage.setItem('userid', userid);
  sessionStorage.setItem('user', user);
});

document.querySelector('#extract').addEventListener('click', () => {
    
    
  console.log(sessionStorage);
});

store 被点击后,就会将对应的数据存储到对应的 storage 中:

在这里插入图片描述

需要注意的是,这里的问题就在于 user 没有存进去,这是因为 local/session storage 没有办法存储复杂的对象,而是只能保存字符串,所以正确的保存方式为:

document.querySelector('#store').addEventListener('click', () => {
    
    
  sessionStorage.setItem('userid', userid);
  sessionStorage.setItem('user', JSON.stringify(user));
});

document.querySelector('#extract').addEventListener('click', () => {
    
    
  console.log(sessionStorage.getItem('userid'));
  console.log(JSON.parse(sessionStorage.getItem('user')));
});

在这里插入图片描述

在这里插入图片描述

local storage 和 session storage 的区别就在于,local storage 相当于做了一个本地的持久化,其中的数据如果不是通过 js 代码、用户删除,浏览器不会主动删除。而 session storage 则是在 session 结束之后(用户关闭当前 tab)后自动删除,如:

在这里插入图片描述

这种存储方法优点是:

  • 可以存储相对比较大的数据(通常来说 5-10mb)

    没记错的话,leetcode 的代码就是存在 local storage 里的

  • 可以根据需求选择使用 session 或是 local

    local storage 存储的数据可以在不同的 tabs 之间被共享

  • 使用方式简单, API 支持更好

这种存储方法缺点是:

  • tabs 之间数据无法共享(针对 session storage)
  • 服务端无法获取数据(除非添加到 header/body 中传输到后端)
  • CORS,不同 domain 之间数据无法共享

cookies

cookies 是另一种存储方式,它存储的也是一个键值对,使用方式如下:

const userid = 'u12345';
const user = {
    
    
  name: 'name',
  age: 18,
  status: 'active',
};

document.querySelector('#store').addEventListener('click', () => {
    
    
  document.cookie = `uid=${
      
      userid}`;
  document.cookie = `user=${
      
      JSON.stringify(user)}`;
});

document.querySelector('#extract').addEventListener('click', () => {
    
    
  console.log(document.cookie.split(';').map((i) => i.trim()));
});

在这里插入图片描述

在这里插入图片描述

cookies 同样可以设置生存周期,如:

document.cookie = `uid=${
      
      userid}; max-age=50`;

这段就会让 cookie 在 50s 后过期:

在这里插入图片描述

另外还有一种 cookie 叫做 httpOnly,这种 cookie 多数用于后端与浏览器之间的交流,无法直接通过 JS 获取。

这种存储方法优点是:

  • 服务端可以获取 cookies

  • 可以用于验证和认证

    虽然这么说,不过因为发起 request 就会携带 cookies,所以大多数情况下 cookies 不会保存敏感信息(病毒代码可以 request 到一些第三方站点,这样会导致数据泄露),只会保留过期时间之类的不是非常敏感的数据

    目前主流代替使用 cookie 的验证方法有 JWT

  • 可以存活多个 sessions

  • 可用于追踪用户数据

    访问一些网站的话,它们也会“请求”cookies 的数据去“提供更好的服务”

这种存储方法缺点是:

  • 数据量小

    一个 cookie 只有 4kb

  • 多个 cookie 可以导致 HTTP 请求过大

    因为 cookie 会存在于每个请求中

  • 安全、隐私考虑

    包括追踪用户信息和被携带访问第三方网站(如通过 Proxy 的方法去访问避开 CORS),前者是个人信息,后者容易导致 XSS

  • 灵活性低

    不同于 local/session storage,有提供良好的 API 去获取数据,cookies 必须要手动进行 split,在不使用第三方库的情况下获取 cookie 较为麻烦

indexedDB

indexedDB 是这里会提到的最后一个比较主流的数据存储解决方案,但是大多数情况下并不会用到,在我个人的实际项目经验里用到的只有一次:为了提供 offline features。当然,感兴趣的也可以看看 vscode 的源码,我之前有瞄到 vscode 也用 indexedDB。

indexedDB 是一个 NoSQL DB,不过这块这里不会细究。

它的使用方式如下:

const userid = 'u12345';
const user = {
    
    
  name: 'name',
  age: 18,
  status: 'active',
};

// non promise based
// will create db if the db doesn't exist, otherwise just open it
const dbRequest = indexedDB.open('StorageDemo', 1);
let db = null;

dbRequest.addEventListener('success', (e) => {
    
    
  db = e.target.result;
});

// calls each time when db version changes or initialized
dbRequest.addEventListener('upgradeneeded', (e) => {
    
    
  db = e.target.result;
  const objStore = db.createObjectStore('products', {
    
    
    keyPath: 'id',
  });

  objStore.transaction.addEventListener('complete', (e) => {
    
    
    const productStore = db
      .transaction('products', 'readwrite')
      .objectStore('products');

    productStore.add({
    
     id: 'p1', title: 'First Product', price: 99.99 });
  });
});

dbRequest.addEventListener('error', (e) => {
    
    
  console.log(e);
});

document.querySelector('#store').addEventListener('click', () => {
    
    
  if (!db) return;

  const productStore = db
    .transaction('products', 'readwrite')
    .objectStore('products');

  productStore.add({
    
     id: 'p2', title: 'Second Product', price: 9.99 });
});

document.querySelector('#extract').addEventListener('click', () => {
    
    
  const productStore = db
    .transaction('products', 'readonly')
    .objectStore('products');

  const request = productStore.get('p2');

  request.addEventListener('success', () => {
    
    
    console.log(request.result);
  });
});

语法就是这么的麻烦,并且所有的执行都是在 callback 中,同样因为使用太复杂了,所以基本上都会用 wrapper 进行操作,读写的结果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

indexedDB 的优点:

  • 数据存储量大

    据说每个 domain 可以存到 1GB,浏览器可以使用 60% 左右的硬盘内存

  • 存储数据格式灵活

    不需要 stringfy,可以直接以对象、数组的方式存储,同时因为是 NoSQL,所以存储的对象格式也非常灵活

  • 异步操作

    非阻塞式运行(这也是为什么这么多 callbacks)

  • 数据库优势

    包括 ACID、indexed search 和 query

indexedDB 的缺点:

  • 特别麻烦……

    语法麻烦,query 麻烦,异步也麻烦……

    所以也就导致开发麻烦,维护麻烦,而且因为 callbacks 太多了,如果使用 JS 提示不太好,我这里代码就写错了,但是 JS 完全没办法提示:

    在这里插入图片描述

    正确的语法应该使用 objectStore 而不是 objStore (这应该是 VSCode 自动提示,然后我没注意按了 tab 导致的)

  • 浏览器支持问题

    近几年还好,只要不是用 ie

    目前 1.0 的话 IE 还是 partial 支持,2.0 的话 IE 是完全不支持,opera mini 也是完全不支持,除此之外的主流浏览器支持还可以。

  • 缺少原生 query 语言

其他

其他一些就是跨浏览器支持不太好,比如说:

  • web sql,目前 firefox 和 Safari 还是完全不支持

  • private state tokens 是 chrome 自己提出来的实现

  • cache storage 与 service worker 有关,暂时不会涉及到这一部分

  • shared storage 应该也是 chrome 特有的,我在火狐上没看到

    在这里插入图片描述

reference

猜你喜欢

转载自blog.csdn.net/weixin_42938619/article/details/130844443