Skip to content

浏览器存储 ​

对比一览 ​

特性CookielocalStoragesessionStorageIndexedDB
容量~4KB~5MB~5MB无上限(通常>250MB)
类型字符串字符串字符串结构化数据
同步/异步同步同步同步异步
作用域同源 + 路径同源同源 + 标签页同源
过期时间可设置永久标签页关闭永久
与服务器通信自动携带不发送不发送不发送
索引搜索不支持不支持不支持支持

Cookie 最初用于在浏览器存储服务器会话信息,每次请求会自动携带在同源的请求头中。

基本操作 ​

js
// 设置 Cookie
document.cookie = "username=maomao; path=/; max-age=86400"

// 读取 Cookie
console.log(document.cookie) // "username=maomao; theme=dark"

// 删除 Cookie(设置过期时间为过去)
document.cookie = "username=; max-age=0"
// 设置 Cookie
document.cookie = "username=maomao; path=/; max-age=86400"

// 读取 Cookie
console.log(document.cookie) // "username=maomao; theme=dark"

// 删除 Cookie(设置过期时间为过去)
document.cookie = "username=; max-age=0"
属性说明
path=/Cookie 生效路径
domain=.example.com可访问的域名
max-age=3600有效期(秒)
expires=GMT时间过期时间
secure仅 HTTPS 传输
HttpOnly禁止 JS 访问(防止 XSS)
SameSite=Strict|Lax|None跨站请求控制
js
const CookieUtil = {
  set(name, value, days = 7) {
    const expires = new Date(Date.now() + days * 864e5).toUTCString()
    document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; expires=${expires}; path=/`
  },

  get(name) {
    const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${encodeURIComponent(name)}=([^;]*)`))
    return match ? decodeURIComponent(match[1]) : null
  },

  remove(name) {
    this.set(name, "", -1)
  },
}
const CookieUtil = {
  set(name, value, days = 7) {
    const expires = new Date(Date.now() + days * 864e5).toUTCString()
    document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; expires=${expires}; path=/`
  },

  get(name) {
    const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${encodeURIComponent(name)}=([^;]*)`))
    return match ? decodeURIComponent(match[1]) : null
  },

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

localStorage ​

持久化存储,除非手动删除否则永久保存。

基本操作 ​

js
// 增/改
localStorage.setItem("theme", "dark")
localStorage.setItem("user", JSON.stringify({ name: "maomao", age: 18 }))

// 查
const theme = localStorage.getItem("theme") // "dark"
const user = JSON.parse(localStorage.getItem("user")) // { name: "maomao", age: 18 }

// 删
localStorage.removeItem("theme")

// 清空
localStorage.clear()

// 获取数量
console.log(localStorage.length)
// 增/改
localStorage.setItem("theme", "dark")
localStorage.setItem("user", JSON.stringify({ name: "maomao", age: 18 }))

// 查
const theme = localStorage.getItem("theme") // "dark"
const user = JSON.parse(localStorage.getItem("user")) // { name: "maomao", age: 18 }

// 删
localStorage.removeItem("theme")

// 清空
localStorage.clear()

// 获取数量
console.log(localStorage.length)

监听 storage 事件 ​

同一浏览器其他标签页修改 localStorage 时触发(当前页不会触发)。

js
window.addEventListener("storage", (e) => {
  console.log("键:", e.key)
  console.log("旧值:", e.oldValue)
  console.log("新值:", e.newValue)
  console.log("来源:", e.url)
})
window.addEventListener("storage", (e) => {
  console.log("键:", e.key)
  console.log("旧值:", e.oldValue)
  console.log("新值:", e.newValue)
  console.log("来源:", e.url)
})

sessionStorage ​

会话级存储,标签页关闭即清除。

js
// 与 localStorage API 完全一致
sessionStorage.setItem("token", "abc123")
const token = sessionStorage.getItem("token")
sessionStorage.removeItem("token")
// 与 localStorage API 完全一致
sessionStorage.setItem("token", "abc123")
const token = sessionStorage.getItem("token")
sessionStorage.removeItem("token")

特点:

  • 不同标签页之间的 sessionStorage 不共享(即使是同一个源)
  • 刷新页面数据仍然存在
  • 关闭标签页或浏览器后数据清除

IndexedDB ​

浏览器的非关系型数据库,支持索引、事务、大量结构化数据存储。

基本操作 ​

js
// 打开/创建数据库
const request = indexedDB.open("MyDatabase", 1)

request.onerror = (event) => {
  console.error("数据库打开失败")
}

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

  // 创建对象存储(类似表)
  if (!db.objectStoreNames.contains("users")) {
    const store = db.createObjectStore("users", {
      keyPath: "id",
      autoIncrement: true,
    })
    // 创建索引
    store.createIndex("name", "name", { unique: false })
    store.createIndex("email", "email", { unique: true })
  }
}

request.onsuccess = (event) => {
  const db = event.target.result
  console.log("数据库打开成功")
}
// 打开/创建数据库
const request = indexedDB.open("MyDatabase", 1)

request.onerror = (event) => {
  console.error("数据库打开失败")
}

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

  // 创建对象存储(类似表)
  if (!db.objectStoreNames.contains("users")) {
    const store = db.createObjectStore("users", {
      keyPath: "id",
      autoIncrement: true,
    })
    // 创建索引
    store.createIndex("name", "name", { unique: false })
    store.createIndex("email", "email", { unique: true })
  }
}

request.onsuccess = (event) => {
  const db = event.target.result
  console.log("数据库打开成功")
}

增删改查 ​

js
const dbName = "MyDatabase"
const storeName = "users"

function openDB() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(dbName, 1)
    request.onsuccess = () => resolve(request.result)
    request.onerror = () => reject(request.error)
  })
}

// 新增
async function addUser(user) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readwrite")
  const store = tx.objectStore(storeName)
  store.add(user)
  await new Promise((resolve) => (tx.oncomplete = resolve))
}

// 查询
async function getUser(id) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readonly")
  const store = tx.objectStore(storeName)
  return new Promise((resolve) => {
    const request = store.get(id)
    request.onsuccess = () => resolve(request.result)
  })
}

// 更新
async function updateUser(user) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readwrite")
  const store = tx.objectStore(storeName)
  store.put(user)
  await new Promise((resolve) => (tx.oncomplete = resolve))
}

// 删除
async function deleteUser(id) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readwrite")
  const store = tx.objectStore(storeName)
  store.delete(id)
  await new Promise((resolve) => (tx.oncomplete = resolve))
}
const dbName = "MyDatabase"
const storeName = "users"

function openDB() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(dbName, 1)
    request.onsuccess = () => resolve(request.result)
    request.onerror = () => reject(request.error)
  })
}

// 新增
async function addUser(user) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readwrite")
  const store = tx.objectStore(storeName)
  store.add(user)
  await new Promise((resolve) => (tx.oncomplete = resolve))
}

// 查询
async function getUser(id) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readonly")
  const store = tx.objectStore(storeName)
  return new Promise((resolve) => {
    const request = store.get(id)
    request.onsuccess = () => resolve(request.result)
  })
}

// 更新
async function updateUser(user) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readwrite")
  const store = tx.objectStore(storeName)
  store.put(user)
  await new Promise((resolve) => (tx.oncomplete = resolve))
}

// 删除
async function deleteUser(id) {
  const db = await openDB()
  const tx = db.transaction(storeName, "readwrite")
  const store = tx.objectStore(storeName)
  store.delete(id)
  await new Promise((resolve) => (tx.oncomplete = resolve))
}

使用场景 ​

存储方式适用场景
Cookie会话标识、登录态、少量需与服务器交互的数据
localStorage主题设置、用户偏好、缓存数据
sessionStorage表单临时数据、页面间传参
IndexedDB离线数据、大量结构化数据、PWA 缓存