浏览器存储方案

Cookie、localStorage、sessionStorage、IndexedDB 的对比与使用

问题

浏览器有哪些存储方案?它们的区别和使用场景是什么?

解答

// 设置 cookie
document.cookie = 'username=john; max-age=3600; path=/';

// 设置带过期时间的 cookie
document.cookie = 'token=abc123; expires=Thu, 01 Jan 2025 00:00:00 GMT';

// 读取所有 cookie
console.log(document.cookie); // "username=john; token=abc123"

// 封装 cookie 操作
const Cookie = {
  set(name, value, days) {
    let expires = '';
    if (days) {
      const date = new Date();
      date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
      expires = `; expires=${date.toUTCString()}`;
    }
    document.cookie = `${name}=${encodeURIComponent(value)}${expires}; path=/`;
  },

  get(name) {
    const cookies = document.cookie.split('; ');
    for (const cookie of cookies) {
      const [key, val] = cookie.split('=');
      if (key === name) return decodeURIComponent(val);
    }
    return null;
  },

  remove(name) {
    this.set(name, '', -1);
  }
};

localStorage

// 存储数据
localStorage.setItem('user', JSON.stringify({ name: 'john', age: 25 }));

// 读取数据
const user = JSON.parse(localStorage.getItem('user'));

// 删除数据
localStorage.removeItem('user');

// 清空所有数据
localStorage.clear();

// 封装 localStorage,支持过期时间
const Storage = {
  set(key, value, expireMinutes) {
    const data = {
      value,
      expire: expireMinutes ? Date.now() + expireMinutes * 60 * 1000 : null
    };
    localStorage.setItem(key, JSON.stringify(data));
  },

  get(key) {
    const item = localStorage.getItem(key);
    if (!item) return null;

    const data = JSON.parse(item);
    // 检查是否过期
    if (data.expire && Date.now() > data.expire) {
      localStorage.removeItem(key);
      return null;
    }
    return data.value;
  }
};

sessionStorage

// API 与 localStorage 完全相同
sessionStorage.setItem('tempData', 'hello');
sessionStorage.getItem('tempData');
sessionStorage.removeItem('tempData');
sessionStorage.clear();

// 区别:关闭标签页后数据清除

IndexedDB

// 打开数据库
const request = indexedDB.open('myDB', 1);

// 数据库升级时创建表
request.onupgradeneeded = (event) => {
  const db = event.target.result;
  // 创建对象仓库(表),keyPath 是主键
  const store = db.createObjectStore('users', { keyPath: 'id' });
  // 创建索引
  store.createIndex('name', 'name', { unique: false });
};

request.onsuccess = (event) => {
  const db = event.target.result;

  // 添加数据
  const tx = db.transaction('users', 'readwrite');
  const store = tx.objectStore('users');
  store.add({ id: 1, name: 'john', email: 'john@example.com' });

  // 读取数据
  const getRequest = store.get(1);
  getRequest.onsuccess = () => {
    console.log(getRequest.result);
  };
};

// 封装为 Promise
class IDB {
  constructor(dbName, storeName) {
    this.dbName = dbName;
    this.storeName = storeName;
  }

  open() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, 1);
      request.onupgradeneeded = (e) => {
        e.target.result.createObjectStore(this.storeName, { keyPath: 'id' });
      };
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async add(data) {
    const db = await this.open();
    const tx = db.transaction(this.storeName, 'readwrite');
    tx.objectStore(this.storeName).add(data);
  }

  async get(id) {
    const db = await this.open();
    return new Promise((resolve) => {
      const request = db.transaction(this.storeName).objectStore(this.storeName).get(id);
      request.onsuccess = () => resolve(request.result);
    });
  }
}

对比表格

特性CookielocalStoragesessionStorageIndexedDB
容量4KB5-10MB5-10MB无限制
过期可设置永久标签页关闭永久
服务端访问自动携带
API字符串操作同步同步异步
数据类型字符串字符串字符串任意

关键点

  • Cookie:容量小(4KB),会随请求发送到服务端,适合存储身份认证信息
  • localStorage:容量大,永久存储,同源共享,适合存储用户偏好设置
  • sessionStorage:仅当前标签页有效,适合存储临时表单数据
  • IndexedDB:异步操作,支持事务和索引,适合存储大量结构化数据
  • 选择原则:小数据用 localStorage,需要服务端读取用 Cookie,大数据或复杂查询用 IndexedDB