什么是Service Worker
一个Service Worker
是一种类型的web worker
。它本质上是一个JavaScript文件,它与主浏览器线程分开运行,拦截网络请求,缓存或从缓存中检索资源,以及传递推送消息。
由于工作者与主线程分开运行,因此Service Worker
独立于与其关联的应用程序。这有几个后果:
因为
Service Worker
没有阻塞(它被设计为完全异步)同步XHR并且localStorage不能在Service Worker
中使用。当应用程序未处于活动状态时,
Service Worker
可以从服务器接收推送消息。这样,即使未在浏览器中打开,您的应用也会向用户显示推送通知。Service Worker
无法直接访问DOM。为了与页面通信,Service Worker
使用postMessage()
方法发送数据,并使用message
事件监听器来接收数据。
关于Service Worker
的注意事项:
Service Worker
是一种可编程网络代理,可让您控制如何处理来自页面的网络请求。Service Worker
只能通过HTTPS运行。由于Service Worker
可以拦截网络请求并修改响应,因此“中间人”攻击可能非常糟糕。注意:像
Let's Encrypt
这样的服务允许您免费获得SSL证书以便在服务器上安装。Service Worker
工作程序在不使用时变为空闲状态,并在下次需要时重新启动。您不能依赖事件之间持久存在的全局状态。如果存在需要在重新启动时保留和重用的信息,则可以使用IndexedDB
数据库。Service Worker
广泛使用Promises
。
Service Worker能做什么
Service Worker
使应用程序能够控制网络请求,缓存这些请求以提高性能,并提供对缓存内容的脱机访问。
Service Worker
依赖于两个API来使应用程序脱机工作: Fetch
(从网络检索内容的标准方法)和Cache
(应用程序数据的持久内容存储)。这个Cache
是持久的,独立于浏览器缓存或网络状态。
提高应用程序/站点的性能
缓存资源将使内容在大多数网络条件下加载更快。有关缓存策略的完整列表,请参阅 使用Caching files with the service worker和The Offline Cookbook。
让您的应用“离线优先”
使用Service Worker
内部的Fetch API
,我们可以拦截网络请求,然后使用所请求资源以外的内容修改响应。当用户离线时,我们可以使用此技术从缓存中提供资源。请参阅 使用Service Worker
缓存文件以获得此技术的实际操作经验。
充当高级功能的基础
Service Worker
提供了使Web应用程序像本机应用程序一样工作的功能的起点。其中一些功能是:
Notifications API:使用操作系统的本机通知系统显示通知并与通信交互的方法。
Push API:一种API,可让您的应用订阅推送服务并接收推送消息。推送消息被传递给
Service Worker
,Service Worker
可以使用消息中的信息来更新本地状态或向用户显示通知。由于Service Worker
独立于主应用程序运行,因此即使浏览器未运行,他们也可以接收和显示通知。Background Sync API:允许您将操作推迟到用户具有稳定连接。这对于确保实际发送用户想要发送的内容非常有用。此API还允许服务器定期更新应用程序,以便应用程序可以在下次联机时进行更新
Channel Messaging API:允许Web工作者和
Service Worker
相互通信并与主机应用程序通信。此API的示例包括新内容通知和需要用户交互的更新。
Service Worker生命周期
Service Worker
在其生命周期中经历三个步骤:
- 注册
- 安装
- 激活
注册和作用域
要安装Service Worker
,您需要在主JavaScript代码中注册它。注册会告诉浏览器您的Service Worker
所在的位置,并开始在后台安装它。我们来看一个例子:
1 | if ('serviceWorker' in navigator) { |
此代码首先检查浏览器支持navigator.serviceWorker
。然后向Service Worker
注册,navigator.serviceWorker.register
返回在Service Worker
成功注册时解析的promise
,然后用记录registration.scope
。
scope
是确定哪些Service Worker
控制的,换句话说,从该路径的Service Worker
将拦截请求。默认范围是Service Worker
文件的位置,并扩展到下面的所有目录。因此,如果service-worker.js
位于根目录中,则Service Worker
将控制来自此域的所有文件的请求。
您还可以通过在注册时传入其他参数来设置任意范围。例如:
1 | navigator.serviceWorker.register('/service-worker.js', { |
在这种情况下,我们设置Service Worker
的作用域到/app/
,这意味着Service Worker
作用域包括/app/
,/app/lower/
以及/app/lower/lower
等,但不包括/app
或者/
,以及其他上一级的路径。
如果已安装Service Worker
,则navigator.serviceWorker.register
返回当前Service Worker
的注册对象。
安装
一旦浏览器注册了Service Worker
,就可以尝试安装。如果浏览器认为Service Worker
是新用户,则会安装Service Worker
,原因是该站点当前没有已注册的Service Worker
,或者因为新Service Worker
与之前安装的Service Worker
之间存在字节差异。
Service Worker
安装会在安装过程中触发事件。我们可以在Service Worker
安装过程中包含一个事件监听器,以便在安装Service Worker
时执行某些任务。例如,在安装过程中,Service Worker
可以预先缓存Web应用程序的某些部分,以便在用户下次打开它时立即加载。因此,在第一次加载之后,您将从即时重复加载中受益,并且在这些情况下,您的交互时间将变得更好。安装事件侦听器的示例如下所示:
1 | // Listen for install event, set callback |
激活
一旦Service Worker
成功安装,它就会转换到激活阶段。如果存在由前一个Service Worker
控制的任何打开页面,则新Service Worker
进入waiting状态。新Service Worker
仅在不再加载仍在使用旧Service Worker
的任何页面时激活。这可确保在任何给定时间只运行一个版本的Service Worker
。
注意:仅刷新页面不足以将控制权转移给新的
Service Worker
,因为在卸载当前页面之前将请求新页面,并且不会有旧Service Worker
未使用的时间。
当新Service Worker
激活时,将激活的Service Worker
中触发事件activate
。此事件侦听器是清理过时缓存的好地方
1 | self.addEventListener('activate', function(event) { |
激活后,Service Worker
将控制在其作用域内加载的所有页面,并开始侦听来自这些页面的事件。但是,在Service Worker
激活之前加载的页面不在Service Worker
控制之下。新Service Worker
只会在您关闭并重新打开应用程序或执行 clients.claim()
时接管。在此之前,新Service Worker
不会截获此页面的请求。这是有意识的,以确保您的网站的一致性。
原文链接: http://yunzaifei.github.io/2018/08/12/PWA实战(2)—Service-Wroker/
版权声明: 转载请注明出处.