Skip to content

localStorage

关于 cookie、sessionStorage、localStorage 三者的区别主要如下:

存储大小: cookie 数据大小不能超过 4k,sessionStorage 和 localStorage 虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大

有效时间:localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage 数据在当前浏览器窗口关闭后自动删除;cookie 设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭

数据与服务器之间的交互方式, cookie 的数据会自动的传递到服务器,服务器端也可以写 cookie 到客户端; sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存

特点

  • 生命周期:持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的
  • 存储的信息在同一域中是共享的
  • 当本页操作(新增、修改、删除)了 localStorage 的时候,本页面不会触发 storage 事件,但是别的页面会触发 storage 事件。
  • 大小:5M(跟浏览器厂商有关系)
  • localStorage 本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
  • 受同源策略的限制

localStorage 也不是完美的,它有两个缺点:

无法像 Cookie 一样设置过期时间 只能存入字符串,无法直接存对象

js
localStorage.setItem('key', { name: 'value' })
console.log(localStorage.getItem('key')) // '[object, Object]'

使用

js
// 设置
localStorage.setItem('username', 'cfangxu')

// 获取
localStorage.getItem('username')

// 获取键名
localStorage.key(0) // 获取第一个键名

// 删除
localStorage.removeItem('username')

// 一次性清除所有存储
localStorage.clear()

缓存

ts
import { version } from '../package.json'

type Awaitable<T> = T | Promise<T>

type StorageValue = string | Record<string, unknown>
export interface Storage {
  getItem: (key: string) => Awaitable<any | null>
  setItem: <T extends StorageValue = StorageValue>(key: string, value: T) => Awaitable<void>
}

export function memoryStorage() {
  const cache = new Map<string, unknown>()
  return {
    getItem(key: string) {
      return cache.get(key)
    },
    setItem(key: string, value: StorageValue) {
      cache.set(key, value)
    },
  } satisfies Storage
}

const ONE_WEEK = 1000 * 60 * 60 * 24 * 7

export function createAsyncStorage(storage: Storage) {
  return {
    async getItem<T = unknown>(key: string, init?: () => T | Promise<T>) {
      const now = Date.now()
      const res = await storage.getItem(key)
      if (res && res.expires > now && res.version === version) {
        return res.data
      }
      if (!init) {
        return null
      }
      const data = await init()
      await storage.setItem(key, { expires: now + ONE_WEEK, version, data })
      return data
    },
    async setItem(key: string, data: unknown) {
      await storage.setItem(key, { expires: Date.now() + ONE_WEEK, version, data })
    },
  }
}
ts
const googleFonts = await ctx.storage.getItem('google:meta.json', () => $fetch<{ familyMetadataList: FontIndexMeta[] }>('https://fonts.google.com/metadata/fonts', { responseType: 'json' }).then(r => r.familyMetadataList))