Service Worker API
注意:此功能在 Web Workers 中可用。
Service Worker 本质上充当着 Web 应用程序、浏览器和网络(在可用时)之间的代理服务器。它们旨在实现包括但不限于:创建有效的离线体验、拦截网络请求,并根据网络是否可用采取相应措施、更新服务器上的资源。它们还将允许访问推送通知和后台同步 API。
注意: Service Worker 是一种 Web Worker。有关 Worker 类型和用例的通用信息,请参阅 Web Workers。
Service Worker 概念与用法
Service Worker 是一个事件驱动的 Worker,它针对特定的源(origin)和路径进行注册。它采用 JavaScript 文件的形式,可以控制与之关联的网页/站点,拦截和修改导航和资源请求,并以非常精细的方式缓存资源,从而让您完全掌控应用程序在某些情况下的行为(最明显的就是网络不可用时)。
Service Worker 在 Worker 上下文中运行:因此,它们没有 DOM 访问权限,并且与驱动您应用程序的主 JavaScript 运行在不同的线程上。它们是非阻塞的,并且被设计为完全异步的。因此,像同步 XHR 和 Web Storage 这样的 API 不能在 Service Worker 中使用。
Service Worker 不能动态导入 JavaScript 模块,如果在 Service Worker 的全局作用域中调用 import(),将会抛出错误。使用 import 语句的静态导入是允许的。
Service Worker 仅在 安全上下文 中可用:这意味着它们的文档是通过 HTTPS 提供的,尽管浏览器也将 https:// 视为安全上下文,以方便本地开发。HTTP 连接容易受到 中间人 攻击的恶意代码注入,并且允许访问这些强大 API 的攻击可能会造成更严重的后果。
注意: 在 Firefox 中,为了测试,您可以允许 Service Worker 在 HTTP(不安全)下运行;只需在 Firefox 开发者工具的选项/齿轮菜单中勾选 **在工具箱打开时,允许 Service Workers 在 HTTP 上运行** 选项。
注意: 与该领域之前的尝试(例如 AppCache)不同,Service Worker 不会假设您试图做什么,然后在这些假设不完全正确时崩溃。相反,Service Worker 为您提供了更精细化的控制。
注意: Service Worker 大量使用 Promise,因为通常它们会等待响应通过,然后它们将以成功或失败的操作进行响应。Promise 架构非常适合这一点。
注册
Service Worker 首先使用 ServiceWorkerContainer.register() 方法进行注册。如果成功,您的 Service Worker 将被下载到客户端,并尝试为用户在其源(origin)内的所有 URL 或您指定的子集进行安装/激活(见下文)。
下载、安装和激活
此时,您的 Service Worker 将遵循以下生命周期:
- 下载
- 安装
- 激活
当用户首次访问受 Service Worker 控制的站点/页面时,Service Worker 会立即下载。
之后,它会在以下情况下更新:
- 导航到作用域内的页面时。
- Service Worker 触发了一个事件,并且在过去 24 小时内没有下载它。
当找到新文件(与现有 Service Worker 字节比较不同,或者这是此页面/站点遇到的第一个 Service Worker)时,会尝试安装。
如果这是第一次提供 Service Worker,则会尝试安装,然后在成功安装后,激活它。
如果已有 Service Worker,则新版本会在后台安装,但尚未激活——此时它被称为“待定 Worker”(worker in waiting)。只有当不再有使用旧 Service Worker 的页面加载时,它才会激活。一旦没有更多页面需要加载,新的 Service Worker 就会激活(成为“活动 Worker”,active worker)。激活可以更早地使用 ServiceWorkerGlobalScope.skipWaiting() 完成,并且现有页面可以使用 Clients.claim() 被活动 Worker 认领。
您可以监听 install 事件;一个标准的操作是在此事件触发时准备好您的 Service Worker 以供使用,例如,使用内置的存储 API 创建一个缓存,并将您希望离线运行应用程序所需的资源放入其中。
还有一个 activate 事件。此事件触发的时间通常是清理旧缓存和其他与 Service Worker 上一版本相关的对象的好时机。
您的 Service Worker 可以使用 FetchEvent 事件响应请求。您可以使用 FetchEvent.respondWith() 方法以任何您想要的方式修改这些请求的响应。
注意: 由于 install/activate 事件可能需要一段时间才能完成,Service Worker 规范提供了一个 waitUntil() 方法。一旦在 install 或 activate 事件上使用 Promise 调用了它,像 fetch 和 push 这样的功能事件将一直等到 Promise 成功解析。
有关构建第一个基本示例的完整教程,请阅读 使用 Service Workers。
使用静态路由控制资源获取方式
Service Worker 可能会产生不必要的性能开销——当页面在一段时间后首次加载时,浏览器必须等待 Service Worker 启动并运行,才能知道加载什么内容以及它应该来自缓存还是网络。
如果您事先知道某些内容应该从何处获取,您可以完全绕过 Service Worker,立即获取资源。可以使用 InstallEvent.addRoutes() 方法来实现此用例以及更多功能。
其他用例构想
Service Worker 也旨在用于例如:
- 后台数据同步。
- 响应来自其他源的资源请求。
- 接收昂贵计算数据的集中式更新,例如地理位置或陀螺仪,以便多个页面可以使用一组数据。
- 用于开发目的的 CoffeeScript、less、CJS/AMD 模块等的客户端编译和依赖管理。
- 后台服务的钩子。
- 基于特定 URL 模式的自定义模板。
- 性能增强,例如预取用户可能很快需要的资源,如相册中的下一张照片。
- API 模拟。
未来,Service Worker 将能够为 Web 平台做许多其他有用的事情,使其更接近原生应用程序的可用性。有趣的是,其他规范可以并且将开始利用 Service Worker 上下文,例如:
接口
CacheCacheStorage-
代表
Cache对象的存储。它提供了 Service Worker 可以访问的所有命名缓存的主目录,并维护了字符串名称与相应Cache对象之间的映射。 Client-
代表 Service Worker 客户端的作用域。Service Worker 客户端可以是浏览器上下文中的一个文档,也可以是受活动 Worker 控制的
SharedWorker。 Clients-
代表一个
Client对象列表的容器;访问当前源上活动 Service Worker 客户端的主要方式。 ExtendableEvent-
在 Service Worker 生命周期中,扩展了分派到
ServiceWorkerGlobalScope的install和activate事件的生命周期。这确保了像FetchEvent这样的功能性事件在 Service Worker 升级数据库模式、删除过时缓存条目等操作完成之前不会被分派。 ExtendableMessageEvent-
当消息通道在
ServiceWorkerGlobalScope与其他上下文之间接收时,分派到 Service Worker 的message事件的对象——扩展了这些事件的生命周期。 FetchEvent-
传递给
onfetch处理程序的参数,FetchEvent代表分派到 Service Worker 的ServiceWorkerGlobalScope的一个 fetch 操作。它包含有关请求和响应的信息,并提供了FetchEvent.respondWith()方法,该方法允许我们将任意响应提供给受控制的页面。 InstallEvent-
传递给
install事件处理函数参数的InstallEvent接口代表一个分派到 Service Worker 的ServiceWorkerGlobalScope的 install 操作。作为ExtendableEvent的子类,它确保在安装期间不会分派像FetchEvent这样的功能性事件。 -
提供了管理 Service Worker 资源预加载的方法。
ServiceWorker-
代表一个 Service Worker。多个浏览上下文(例如,页面、Worker 等)可以与同一个
ServiceWorker对象关联。 ServiceWorkerContainer-
提供了一个代表 Service Worker 作为网络生态系统中整体单元的对象,包括注册、注销和更新 Service Worker 的功能,以及访问 Service Worker 及其注册的状态。
ServiceWorkerGlobalScope-
代表 Service Worker 的全局执行上下文。
ServiceWorkerRegistration-
代表一个 Service Worker 注册。
WindowClient-
代表一个 Service Worker 客户端的作用域,该客户端是浏览器上下文中的一个文档,由活动 Worker 控制。这是
Client对象的一种特殊类型,具有一些额外的可用方法和属性。
其他接口的扩展
Window.caches和WorkerGlobalScope.caches-
返回与当前上下文关联的
CacheStorage对象。 -
返回一个
ServiceWorkerContainer对象,该对象提供访问与关联文档的ServiceWorker对象的注册、删除、升级和通信。
规范
| 规范 |
|---|
| Service Workers |