Skip to content

参考:状态机 / 事件 / 能力矩阵 / 易错点

基于 W3C Service Workers 现行标准与各浏览器 Baseline 状态 · 核于 2026-07

速查

  • 接口全景ServiceWorkerContainernavigator.serviceWorker)/ ServiceWorkerRegistrationinstalling/waiting/active/update/pushManager/sync/periodicSync/navigationPreload)/ ServiceWorkerstate/scriptURL/postMessage)/ ServiceWorkerGlobalScopeself)/ Clientsclaim/matchAll/openWindow)。
  • 注册navigator.serviceWorker.register(url, { scope });scope 默认=脚本目录、不能宽于路径(除非 Service-Worker-Allowed 头);仅 HTTPS/localhost。
  • 状态机installing → installed(waiting) → activating → activated → redundantinstall 预缓存、activate 收尸、waiting 默认等所有旧标签关闭。
  • 提前接管self.skipWaiting()(install 里跳过 waiting)+ self.clients.claim()(activate 里接管现页);controllerchange 后常 reload
  • 更新:逐字节比对 sw.js(含 importScripts)→ 有变即更新;导航时检查 + 至少每 24h 检查;registration.update() 手动催;sw.js 别设长 HTTP 缓存。
  • fetch 拦截fetch 事件 + event.respondWith(Response|Promise);不调用即放行;event.requestmethod/mode/destination 过滤。
  • 缓存策略/Cache API 在浏览器章:cache-first/network-first/SWR、caches/Cache/clone()/opaque/版本化清理 → 浏览器章(本叶只在拦截处链接)。
  • navigation preloadregistration.navigationPreload.enable() + event.preloadResponse,消除 SW 冷启动延迟(导航请求专属)。
  • Pushregistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })PushSubscriptionendpoint+keys)→ SW push 事件 → registration.showNotification();Baseline 含 Safari 16.4+,iOS 需装 PWA
  • Background Syncregistration.sync.register(tag) → SW sync 事件 → event.waitUntil 补发;event.lastChance仅 Chromium
  • Periodic Syncregistration.periodicSync.register(tag, { minInterval }) → SW periodicsync 事件;仅 Chromium + 仅已装 PWA + 参与度门槛
  • Manifest<link rel="manifest">application/manifest+json;关键字段 name/short_name/icons(192+512)/start_url/display/theme_color/scope
  • displaystandalone/fullscreen/minimal-ui/browserdisplay_override 有序回退链。
  • 安装条件(Chromium):HTTPS + 合规 manifest(name、192+512 图标、start_url、display 非 browser、prefer_related_applications 非 true);SW 曾必需、现已放宽(但离线仍需 SW)。
  • beforeinstallpromptChromium 私有preventDefault()+存事件 → prompt()userChoiceaccepted/dismissed);appinstalled 收尾;iOS 无此事件、走"添加到主屏幕"。
  • 通用心法:后台能力都要 event.waitUntil;周边能力都要特性探测降级;SW 会被终止再唤醒,状态放 Cache/IndexedDB。

一、接口全景

接口职责
ServiceWorkerContainer页面侧入口 navigator.serviceWorkerregister/getRegistration/ready/controllercontrollerchange/message 事件
ServiceWorkerRegistration一次注册;installing/waiting/active 三槽位 + scope/update()/unregister()/pushManager/sync/periodicSync/navigationPreloadupdatefound 事件
ServiceWorker一个 SW 实例;state/scriptURL/postMessage()statechange 事件
ServiceWorkerGlobalScopeSW 全局作用域 selfskipWaiting()/registration/clients/cachesinstall/activate/fetch/push/sync/periodicsync/message/notificationclick 事件
Clients / Client / WindowClient受控页面集合;claim()/matchAll()/openWindow()/get()WindowClientfocus()/navigate()
ExtendableEventinstall/activate 等的基类;waitUntil(promise) 延长生命周期
FetchEventfetch 事件;request/respondWith()/preloadResponse
PushManager / PushSubscription / PushMessageData推送订阅 / 订阅对象(endpoint+keys)/ 载荷读取
SyncManager / PeriodicSyncManager一次性 / 周期性后台同步登记器
NavigationPreloadManager导航预加载开关;enable()/disable()/setHeaderValue()

二、生命周期状态机

状态(ServiceWorker.state含义对应槽位
installing正在安装(install 事件进行中/waitUntil 未决)registration.installing
installed安装完成,等待激活(即 waitingregistration.waiting
activating正在激活(activate 事件进行中)
activated已激活,处理 fetch/push/syncregistration.active
redundant被替换或安装/激活失败,作废

接管控制的四个动作

API时机作用
event.waitUntil(promise)install/activate/功能事件延长事件寿命,promise 完成前不进入下一状态/不被终止
self.skipWaiting()通常在 install跳过 waiting,装完立即激活
self.clients.claim()通常在 activate立即接管当前已打开的受控页面
registration.update()页面侧任意时刻手动触发一次更新检查

三、SW 事件表

事件触发于典型用途
installSW 首装/更新waitUntil 预缓存 App Shell
activate新 SW 接管时收尸旧缓存、clients.claim()、开 navigation preload
fetch作用域内每个网络请求respondWith 决定回缓存/网络/合成响应
push服务器推送到达showNotification() 弹通知
notificationclick用户点击通知聚焦/打开窗口
sync恢复网络(一次性同步)补发离线期间的请求
periodicsync浏览器裁量的周期点定期预取内容
message页面 postMessage页面↔SW 通信(如通知 skipWaiting
pushsubscriptionchange推送订阅失效/过期重新订阅并更新服务器
updatefound(在 registration 上)发现新版本开始安装自建"有新版本"提示
controllerchange(在 container 上)控制本页的 SW 变更切新版后 reload

四、Push / Sync / Manifest 速查

4.1 Push API

API说明
registration.pushManager.subscribe(opts)订阅;opts.userVisibleOnly(Chrome 必 true)、opts.applicationServerKey(VAPID 公钥)
pushManager.getSubscription()取现有订阅(不新建)
PushSubscriptionendpoint(保密)、keys.p256dh/keys.auth(加密)、toJSON()unsubscribe()
push 事件event.dataPushMessageData.json()/.text()/.arrayBuffer())、event.waitUntil()
registration.showNotification(title, opts)SW 里弹通知(new Notification());optsbody/icon/badge/data/actions
Notification.requestPermission()页面侧请求权限,需用户手势

4.2 Background Sync / Periodic Sync

API说明
registration.sync.register(tag)登记一次性同步;getTags() 查已登记
sync 事件event.tagevent.lastChanceevent.waitUntil()
registration.periodicSync.register(tag, { minInterval })登记周期同步(minInterval 为下限)
periodicSync.getTags() / unregister(tag)查 / 取消
periodicsync 事件event.tagevent.waitUntil()

4.3 Manifest 关键字段

字段安装相关说明
name / short_name✅(至少一个)应用名 / 主屏短名
icons✅(需 192+512){ src, sizes, type, purpose }purpose: maskable 自适应
start_url启动地址
display✅(非 browser)standalone/fullscreen/minimal-ui/browser
display_override有序回退链,优先于 display
theme_color / background_color主题色 / 启动屏背景
scope导航范围
id稳定唯一标识(防重复安装)
shortcuts / screenshots / categories / description快捷入口 / 富安装弹窗截图 / 分类 / 描述
prefer_related_applications✅(须非 true)true 表示更推荐原生应用,不弹 Web 安装

五、浏览器支持矩阵

能力Chrome/EdgeFirefoxSafari备注
Service Worker 核心(注册/生命周期/fetch/Cache API)全浏览器 Baseline
Navigation Preload较新 Safari 已支持
Push API✅(16.4+)Baseline 2023-03iOS 需先装 PWA
Notification(SW 内 showNotification需用户授权
Background Sync(sync仅 Chromium
Periodic Background Sync(periodicsync仅 Chromium + 仅已装 PWA + 参与度门槛
beforeinstallpromptChromium 私有事件
PWA 安装✅(自动提示)部分✅("添加到主屏幕")iOS 16.4+ 各浏览器可从分享菜单装
InstallEvent.addRoutes()(静态路由)部分(较新)需特性探测

支持面随版本演进,生产落地前以 caniuse / MDN 的 Baseline 标注为准,周边能力一律特性探测 + 降级。

六、安装条件清单(Chromium)

  • [ ] 整站 HTTPS(或本地 localhost/127.0.0.1
  • [ ] 页面 <head><link rel="manifest"> 且能正确加载(MIME application/manifest+json
  • [ ] manifest 有 name short_name
  • [ ] icons 至少含 192×192512×512 各一
  • [ ] 有 start_url
  • [ ] displaystandalone / fullscreen / minimal-ui(非 browser
  • [ ] prefer_related_applicationsfalse 或不写
  • [ ] (强烈建议但非硬性)注册了 SW——离线体验的前提,且 SW/fetch 处理器在旧 Chromium 曾是安装硬门槛
  • [ ] iOS:另配 apple-touch-icon + apple-mobile-web-app-* meta,引导用户"添加到主屏幕"

七、易错点清单

  • 改了 sw.js 刷新没生效:新 SW 在 waiting,普通刷新不换版——关所有标签重开 / skipWaiting / DevTools「Update on reload」。
  • skipWaiting 但页面还是旧的skipWaiting 只激活新 SW,接管现页要 clients.claim()——两者常配对。
  • 首访不走缓存:默认 SW 不控制注册它的当前页——clients.claim() 让首访即生效。
  • sw.js 被长 HTTP 缓存:更新延迟——给 SW 脚本设 Cache-Control: max-age=0
  • 只改资源没改 sw.js:字节没变不更新——版本号/清单写进 sw.js
  • 在 SW 顶层存运行状态:SW 被终止再唤醒会丢——状态放 Cache/IndexedDB。
  • fetch 里接管了 POST:Cache API 只支持 GET——写请求先放行。
  • respondWith 分支 reject 没兜底:页面拿到网络错误——每条路径都 catch,导航兜底离线页。
  • navigator.onLine 判离线:不可靠——离线兜底靠 fetchcatch
  • 推送用 new Notification():SW 里没有——用 registration.showNotification()
  • 没要 Notification 权限就订阅推送userVisibleOnly 推送发不出——先 requestPermission()(用户手势)。
  • iOS 上直接订阅推送:普通 Safari 标签页不行——必须先"添加到主屏幕"装成 PWA。
  • 在 Firefox/Safari 上等 beforeinstallprompt:永远等不到——能力探测,iOS 走"添加到主屏幕"引导。
  • prompt() 调多次:一个事件只一次——用完置空、隐藏按钮。
  • 以为"能装"=「能离线」:安装门槛放宽后没 SW 也能装,但断网白屏——离线另配 SW。
  • 图标缺 192/512 或 display: browser:不判定为可安装——补齐尺寸、改 standalone
  • sync/periodicsync 当准时定时器:触发时机由浏览器裁量——设计成"尽力而为"。
  • 周边能力不做特性探测:Background Sync/Periodic Sync/beforeinstallprompt 大面积缺失——先探测再用,全程降级。

八、权威链接