html页面离线渲染靠service worker缓存html/css/js,indexeddb仅负责数据持久化;ui同步需手动调用idb.get()与render(),缺一不可。

HTML 页面离线后能渲染,靠的不是 IndexedDB,而是 Service Worker 缓存了 HTML/CSS/JS;IndexedDB 只负责把数据“存住”,UI 同步必须手动触发——不写 idb.get() + render(),页面永远显示空。
Service Worker 必须先缓存 HTML,否则 IndexedDB 根本没机会运行
关网刷新白屏,90% 是因为 navigator.serviceWorker.register() 没生效,或缓存列表漏了 "/" 或 "/index.html"。IndexedDB.open() 连执行都做不到,更别说读数据渲染 UI。
- 注册 SW 的脚本不能放在
<script defer></script>里却不 await,得等 DOMContentLoaded 后再调用 -
cache.addAll(["/", "/index.html", "/main.js", "/style.css"])是硬性起点,缺一个,页面就加载失败 - 检查 DevTools → Application → Service Workers:状态必须是 “Active”,且点击 “Update on reload” 能看到最新版本
- SW 脚本响应头不能含
Cache-Control: no-store,否则 Chrome 直接拒载
IndexedDB 数据读取后必须显式绑定到 DOM,没有自动映射
IndexedDB 不会像 Vue 的响应式数据那样自动更新视图。你存了 20 条待办,idb.getAll("todos") 返回数组后,得自己调用 renderTodoList(todos) 才能在页面上看见。
- 不要在
onsuccess回调里只 console.log,要立刻触发 UI 渲染逻辑 - 首次加载时,建议用
Promise.all([idb.get(...), idb.getAll(...)])并行读多个 objectStore,避免串行阻塞 - 如果页面有路由(如 /inbox /drafts),需根据当前 URL 从 IndexedDB 中查对应 folder 的 records,再渲染
- 对富文本、附件预览等重渲染操作,建议加 loading 状态,避免用户误点多次
离线时 UI 状态必须和 IndexedDB 记录 status 字段严格对齐
用户点击“发送邮件”,网络断开,你存了 status: "pending" 到 messages 表,但 UI 如果还显示“未发送”,就会造成认知错位。
- 所有关键状态(草稿/待同步/已发送/失败)必须在写入 IndexedDB 的同时,同步更新 DOM 元素的 class 或 data-status 属性
- 用
transaction.oncomplete而非put().onsuccess做最终确认,确保事务真正落盘后再改 UI - 监听
window.navigator.onLine只作提示参考,真实同步触发应以 Service Worker 的fetch或sync事件为准 - 避免“UI 已提交 → 后端失败 → DB 回滚 → UI 却没回退”的情况:失败时,先标记
status: "failed",再弹 toast 提示重试
iOS Safari 和隐私模式下,IndexedDB 初始化时机极敏感
在 iOS Safari 中,indexedDB.open() 若不在用户手势(点击、触摸)后调用,可能静默失败;无痕模式下数据库是临时的,关闭标签即清空。
- 不要在页面 load 时就 open DB,改为首次点击“新建邮件”或“添加待办”按钮时才初始化
- 用
navigator.storage.estimate()检查配额,iOS 隐私模式默认只有 50MB,且不提示 - 数据库名别用
"my-app/v1",斜杠非法,改用"my-app-v1";版本号必须是正整数,不能是字符串 - 每次打开 DB 前,检查
window.indexedDB是否存在,Safari 私密模式可能直接返回 undefined
最常被跳过的环节是:缓存 HTML 和初始化 IndexedDB 之间没有建立依赖链路。SW 激活后,页面资源可离线加载,但 JS 运行时若发现 indexedDB.open() 失败又没 fallback,整个数据层就塌了——它不像 localStorage 那样“写就完事”,而是一整套需要手动衔接的状态同步流水线。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











