Skip to content

localStorage 版本迁移与事件 ​

先从一个浏览器可观察问题开始:同一操作为什么会改变节点、事件、请求、存储或辅助技术状态?本节把“localStorage 版本迁移与事件”拆成输入、所有者、中间状态和输出,避免只背 API。

最小实验 ​

先在控制台写入一个旧版本快照,再运行迁移函数。实验的可观察结果是:旧数据被补上 density 并保存为版本 2;损坏 JSON 会回到默认值。

js
localStorage.setItem('settings', JSON.stringify({ version: 1, theme: 'dark' }))

function readSettings() {
  const fallback = { version: 2, theme: 'light', density: 'comfortable' }
  try {
    const value = JSON.parse(localStorage.getItem('settings') || 'null')
    if (!value || value.version !== 1 && value.version !== 2) return fallback
    const migrated = value.version === 1 ? { ...fallback, ...value, version: 2 } : { ...fallback, ...value }
    localStorage.setItem('settings', JSON.stringify(migrated))
    return migrated
  } catch {
    localStorage.setItem('settings', JSON.stringify(fallback))
    return fallback
  }
}

console.log(readSettings())

把快照改成非法 JSON 后重跑,记录返回值和存储值;再在两个同源标签页中修改设置,观察只有另一个标签页收到 storage 事件。

规则与边界 ​

  • 平台保证、浏览器实现和业务约定必须分开;一个浏览器中的结果不能自动推广到所有宿主。
  • 每个监听器、请求、观察器、缓存和焦点操作都要有清理/取消责任;页面或组件离开后不能继续写状态。
  • 用户输入、URL、HTML、消息和持久化数据按不同信任边界处理;类型正确不代表内容可信。
  • 失败、取消、超时、权限拒绝、配额不足和不支持要有不同的可观察结果。

机制拆解 ​

localStorage 只保存字符串,版本迁移必须区分旧快照、当前 schema 和损坏数据。storage 事件在其他同源文档中触发,当前写入它的页面不会收到同一事件。

可运行实验 ​

js
const raw = localStorage.getItem('settings')
const old = raw ? JSON.parse(raw) : { version: 1, theme: 'light' }
const current = old.version === 1 ? { version: 2, theme: old.theme, density: 'comfortable' } : old
localStorage.setItem('settings', JSON.stringify(current))
addEventListener('storage', event => console.log(event.key, event.newValue))

打开两个标签页,在其中一个写入设置;观察另一个标签页收到事件,关闭一个标签页后说明持久化数据是否仍存在。

练习 ​

  1. 给出版本 1、版本 2、损坏 JSON 和缺少 settings 四种输入,写出迁移后的对象与最终存储字符串。
  2. 在两个同源标签页中同时修改设置,记录哪个页面收到 storage 事件,并解释当前写入页面为什么不会收到同一事件。
  3. 说明何时应改用 IndexedDB:比较数据量、事务、异步操作和可查询性,而不是只说“性能更好”。

查看本节答案

下一步 ​

完成答案核对后继续本章下一篇,并把实验日志保存在自己的项目中。

用心记录每一步成长