background-sync官方Demo逐行拆解:IndexedDB同步计数+通知的完整实现教程
background-sync官方Demo逐行拆解IndexedDB同步计数通知的完整实现教程【免费下载链接】background-syncA design and spec for ServiceWorker-based background synchronization项目地址: https://gitcode.com/gh_mirrors/ba/background-syncbackground-sync 是一个基于 Service Worker 的后台同步Background Sync设计规范项目它让网页在页面关闭或网络恢复后依然能后台补发数据。官方在demo/目录下提供了一个极简的同步 Demo用 IndexedDB 记录每次同步的计数同步完成后通过 Web 通知把结果喊给你看。本文带你逐行拆解这个官方 Demo看懂它如何用不到 100 行代码实现完整的后台同步计数 通知流程。 先认识 Demo3 个文件讲完整个后台同步整个演示只有 3 个文件结构一目了然文件角色核心职责demo/index.html页面端注册 Service Worker、监听网络状态、发起同步注册demo/sw.jsService Worker 端监听sync事件、操作 IndexedDB 计数、弹通知demo/sample.json模拟数据一份带list_version的列表数据假装是服务器最新内容想完整理解为什么需要后台同步可以先读项目里的说明文档explainers/sync-explainer.md周期性同步的设计则在explainers/periodicsync-explainer.md和spec/PeriodicBackgroundSync-index.bs中。 一句话总结 Demo 的目标用户点一下按钮 → 注册一次同步 → 浏览器在合适时机唤醒 Service Worker → 拉数据、计数 1、弹通知。️ 页面端拆解demo/index.html在做什么第一步注册 Service Worker同步的地基页面加载后先检查浏览器是否支持 Service Worker然后注册sw.jsif (serviceWorker in navigator) { navigator.serviceWorker.register(sw.js, { scope: /background-sync/demo/ }) .catch(function(err) { log(ServiceWorker failed to register. Are you visiting the HTTPS site?); }); }两个新手必知要点必须 HTTPS或 localhost否则注册直接失败报错文案里也提示了这一点注册的{ scope }限定了 Worker 的控制范围即demo/目录下的页面。第二步实时显示网络状态在线/离线指示灯Demo 用两个浏览器事件在页面上打了一个网络状态灯window.addEventListener(online, updateOnlineStatus); window.addEventListener(offline, updateOnlineStatus);这一步看似和同步无关其实是理解后台同步的关键你先手动断网点按钮注册同步再恢复网络——sync事件会在网络恢复后才真正触发。这就是后台同步的价值数据不会因为一次断网而丢浏览器会替你记着、择机补跑。第三步一个按钮串起权限 → 注册全流程点击Register background sync按钮后代码按这条链路执行申请通知权限—— 后台同步本身不需要权限但 Demo 要用通知来证明同步跑成功了等待 Worker 就绪——navigator.serviceWorker.ready注册一次同步——reg.sync.register(syncTest)syncTest就是同步标签tag之后会原样传给 Worker 端的sync事件。return reg.sync.register(syncTest);注册成功不等于立刻执行。浏览器会根据网络、电量等条件合并、延迟触发时机这正是它省电的原因详见explainers/sync-explainer.md中对 coalescing 的描述。⚙️ Worker 端拆解demo/sw.js是全文的灵魂入口监听sync事件self.addEventListener(sync, function(sync_event) { // ... 同步逻辑 });浏览器决定现在可以同步了时就会向 Worker 派发这个事件。所有后续逻辑都挂在它身上。第一棒拉取模拟数据cache: no-storefetch(new Request(/background-sync/demo/sample.json, {cache: no-store})) .then(response { if (response.status 200) { return response.text(); } else { throw new Error( response.status response.statusText); } })这里模拟了向服务器要最新数据。注意{cache: no-store}同步时拿到的必须是新鲜数据缓存数据会失去意义。非 200 状态直接抛错进入后面的错误通知分支。sample.json的内容很直白——一个带id和color的 4 项列表外加list_version: 1.2版本号稍后会被写进通知文案。第二棒打开 IndexedDBopenBgSyncDBopen_request indexedDB.open(BgSyncDemoDB, 1); // ... onupgradeneeded: 创建 objectStore syncskeyPath 为 type数据库名BgSyncDemoDB版本 1建表syncs用type作为主键——将来可以存多种同步如one-shot、periodic互不干扰整个函数用 Promise 包装方便和前面的fetch串成链。第三棒核心计数器updateSyncTime逐行看这是 Demo 最精华的 20 行逻辑是取出旧值 → 时间戳 计数 1 → 写回var store db.transaction([syncs], readwrite).objectStore(syncs); var get_request store.get(syncType); // 按 type 取记录 get_request.onsuccess function(event) { var data get_request.result || { type: syncType }; // 第一次同步时没有记录 data.time syncTime; // 更新最近同步时间 data.syncCount (data.syncCount || 0) 1; // 计数器 1 store.put(data); // 写回 // 成功后 resolve(data.syncCount) };新手容易卡住的两个点get_request.result || { type: syncType }首次同步时表是空的result为undefined这里兜底创建一个新记录data.syncCount || 0老记录可能还没有syncCount字段比如数据库升级场景先归零再自增避免算出NaN。为什么计数要存 IndexedDB 而不是内存因为Service Worker 随时会被杀页面也会反复打开。IndexedDB 是持久化的计数才能活过每一次 Worker 生命周期——这也是真实业务中存待发送队列outbox的标准做法。收尾弹通知 出错兜底成功路径——把计数和数据版本号一起喊出来self.registration.showNotification(Sync fired! ( syncCount ) Fetched list v responseData.list_version);失败路径——同样弹通知并把错误消息转发给所有打开的页面function postErrorToClients(err) { clients.matchAll({includeUncontrolled: true}) .then(clientList { clientList.forEach(client client.postMessage(err.message)); }); }页面端之前注册了window.addEventListener(message, displayErrorFromWorker)来接收它在日志区显示Error: ...。一个完整闭环Worker 干完活无论成败都有人知道。 把整条数据流串起来页面注册sw.jsHTTPS 环境→点击按钮授予通知权限 →reg.sync.register(syncTest)登记一次同步 →网络就绪时浏览器派发sync事件 →fetch拉取sample.json最新数据 →IndexedDB 中syncCount 1、更新时间戳 →showNotification展示Sync fired! (N) Fetched list v1.2。断网重连、页面关闭都不影响第 37 步——这就是 background-sync 的完整体验。 动手跑起来git clone https://gitcode.com/gh_mirrors/ba/background-sync在 HTTPS 或 localhost 环境下用支持 Service Worker 的 Chrome 打开demo/index.html体验断网 → 点按钮 → 恢复网络 → 收到通知的完整节奏。⚠️ 新手最容易踩的 3 个坑非 HTTPS 环境注册失败Service Worker 只信任安全环境本地开发请用http://localhost同步没立刻触发浏览器会合并调度断网再恢复是最可靠的触发方式别以为代码写错了通知不弹多半是第 3 步权限被拒了——同步注册成功 ≠ 通知权限到手Demo 里是分开处理的。 延伸从 Demo 到规范spec/index.html/spec/index.bs一次性同步的完整规范spec/PeriodicBackgroundSync-index.bs周期性同步规范explainers/sync-explainer.md动机与 API 全解含powerState、networkState等调度选项use-cases.md邮件发送、内容更新等真实场景。看懂这 3 个文件你就握住了 Web 后台同步的第一块拼图。下一步不妨试试把syncCount改成存一条待办任务队列体验真正的离线 outbox 模式【免费下载链接】background-syncA design and spec for ServiceWorker-based background synchronization项目地址: https://gitcode.com/gh_mirrors/ba/background-sync创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考