浏览器存储
对比一览
| 特性 | Cookie | localStorage | sessionStorage | IndexedDB |
|---|---|---|---|---|
| 容量 | ~4KB | ~5MB | ~5MB | 无上限(通常>250MB) |
| 类型 | 字符串 | 字符串 | 字符串 | 结构化数据 |
| 同步/异步 | 同步 | 同步 | 同步 | 异步 |
| 作用域 | 同源 + 路径 | 同源 | 同源 + 标签页 | 同源 |
| 过期时间 | 可设置 | 永久 | 标签页关闭 | 永久 |
| 与服务器通信 | 自动携带 | 不发送 | 不发送 | 不发送 |
| 索引搜索 | 不支持 | 不支持 | 不支持 | 支持 |
Cookie
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"Cookie 属性
| 属性 | 说明 |
|---|---|
path=/ | Cookie 生效路径 |
domain=.example.com | 可访问的域名 |
max-age=3600 | 有效期(秒) |
expires=GMT时间 | 过期时间 |
secure | 仅 HTTPS 传输 |
HttpOnly | 禁止 JS 访问(防止 XSS) |
SameSite=Strict|Lax|None | 跨站请求控制 |
Cookie 的工具函数
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 缓存 |
Cao Note