Service Worker 是最近几年在 现代网络浏览器 中引入的一个相对较新的 API。 这是一项非常重要的技术。 它是一种特殊的 web worker,可以安装在您的浏览器中,以提供以前普通网页无法提供的特殊功能,例如允许离线访问网站内容。
Service Worker 是 Progressive Web Apps 的核心,因为它们允许缓存资源和推送通知,这是迄今为止将原生应用程序区分开来的两个主要区别特性。
Progressive Web App 保护伞下的功能主要面向 使用 Web 技术 构建功能齐全的移动应用程序的能力,与本机堆栈。
Service Worker 在单独的线程上运行。 这意味着您无法访问主 JavaScript 线程中可用的许多对象,包括访问 DOM 和 XHR 或 Cookie 等多个 API。 从好的方面来说,任何 Service Worker 操作都不会阻塞 UI 线程,因为它是完全独立的。
请记住,服务工作者需要通过 HTTPS 提供服务,否则浏览器不会注册它们。
Service Worker 的主要特点
渐进式 Web 应用程序 (PWA) 的最终目标是在移动设备上表现出色,而 Web 在移动设备上总是失败的一件事就是处理离线状态。
Service Worker 可以拦截网络请求,使用Cache API将它们添加到浏览器缓存中,如果他们检测到浏览器离线并且网络不可用,他们可以提供缓存的资源.
另一个重要功能是启用 推送通知 ,通过使用 Push API 和 Notifications API,开发人员可以在服务工作者中使用的两个独立的 Web 平台 API .
如何安装 Service Worker
Service Worker 需要在浏览器中安装后才能使用。
首先,您需要检查浏览器是否实现了服务工作者。
最好的方法是检查 导航器对象 上是否存在 serviceWorker
:
if (!('serviceWorker' in navigator)) { // service workers not supported 😣 return }
如果 Service Worker 可用,您可以通过指定可以找到它的文件来注册您的 Service Worker。 您始终有一个单独的文件,可供浏览器访问。 例如,您可以将它放在根目录下的 worker.js
文件中。
您等到页面加载完毕,然后使用 navigator.serviceWorker.register()
方法注册服务工作者:
window.addEventListener('load', () => { if (!('serviceWorker' in navigator)) { // service workers not supported 😣 return } navigator.serviceWorker.register('/worker.js').then( () => { // registered! 👍🏼 }, err => { console.error('SW registration failed! 😱', err) } ) })
服务工作者生命周期
我提到需要在浏览器中安装服务工作者才能使用它。
当用户第一次访问您的网站时,Service Worker 唯一能做的就是安装。
在用户访问您网站上的第二个页面或刷新当前页面之前,Service Worker 内部的任何内容及其附带的任何功能都不会启用。 这是设计使然。
Service Worker 中有什么
我们刚刚看到了如何安装一个存在于 worker.js
文件中的服务工作者,但我们还没有研究那个文件。
在 service worker 中,你可以监听浏览器发出的几个事件:
- 每当您的站点页面需要网络资源时,就会发送
fetch
。 它可以是一个新页面、一个 JSON API、一个图像、一个 CSS 文件,等等。 install
在安装 service worker 时发送。activate
在服务工作者注册并安装后发送。 这个地方是你可以清理任何与旧版本的 service worker 相关的东西(如果它已经更新的话)的地方。- 如果浏览器之前检测到连接不可用,则发送
sync
,现在向服务工作者发出 Internet 连接正在工作的信号。 - 当接收到新的推送事件时,推送 API 调用
push
。
提供缓存资源
安装 service worker 后,我们可以告诉浏览器缓存我们需要在稍后离线时为页面提供服务的特定资源:
self.addEventListener('install', event => { event.waitUntil( caches .open('my-site-name') .then(cache => cache.addAll([ 'favicon.ico', 'style.css', 'script.js', 'https://fonts.googleapis.com/css?family=Inconsolata:400,700' ]) ) ) })
这段代码使用 Cache API 使浏览器将所有这些资源缓存在名为 my-site-name
的缓存中。
让我们看看如何监听 fetch
事件,以便在下次访问我们网站的页面时为用户提供缓存资源:
self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then(response => { if (response) { //we found an entry in the cache! return response } return fetch(event.request) }) ) })
我们检查缓存是否包含由 request
属性标识的资源,如果没有,我们启动 获取请求 来获取它。
还要注意上面例子中 self
的使用。 工人获得一个全局的 self
只读属性来允许访问自己。
更新 Service Worker
一旦安装了 service worker,它将继续运行,直到它被用户删除或者你更新它。
要更新服务工作者,您只需在服务器中推送它的新版本(即使更改一个字节就足够了),浏览器会检测到它是新版本,它会下载并安装它。
就像第一次安装时一样,新的 service worker 将在下一页加载之前不可用。