Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Service Worker 的背景

前生:AppCache

AppCache 最初是作为 HTML5 规范的一部分引入,用以解决离线 web 应用程序的问题。

AppCache 最终被发现是不实用的和充满陷阱的。因此它已被废弃,被 Service Workers 有效的取代。

今世:Service worker

Service worker 提供了一个更具前瞻性的离线应用解决方案,通过更加程序化的语言书写规则替代 AppCache 的声明式书写方式。

Service Worker 在浏览器后台进程中持续的执行其代码。它是事件驱动的,这意味着在 Service Worker 的作用域范围内触发的事件会驱动其行为。

注册 Service Worker

在前端代码中某一处执行以下代码即可

        if (navigator.serviceWorker) {
          navigator.serviceWorker.register('./service-worker.js', {scope: './'})
              .then(function (registration) {
                  console.log(registration);
              })
              .catch(function (e) {
                  console.error(e);
              })
        } else {
            console.log('Service Worker is not supported in this browser.')
        }
      

这将告诉浏览器在哪里找到你的 Service Worker 的实现,浏览器将查找对应的(/service-worker.js)文件,并将它保存在你正在访问的域名下,这个文件将包含所有你自己定义的 Service Worker 事件处理程序

注意:

在执行注册的操作的同时也确认了你的ServiceWorker的作用范围是在URL的根路径下。这意味着在你的根路径下的任何请求,都将通过触发事件的方式告诉 Service Worker。一个文件路径为/js/service-worker.js的文件就仅仅可以捕获http://{host}/js该链接下的请求。

另外,你也可以通过将第二个参数传入给register方法来明确地设置 Service Worker 的作用域范围:

          navigator.serviceWorker.register('/sw.js', { scope: '/js' })
      

Service Worker 的生命周期

使用 service worker 实现离线缓存

实际上离线缓存功能,就是我们根据WebApp的需要,事先将缓存策略写入到service-worker.js中。接下来通过分析service-worker.js的代码来介绍该功能的实现。

缓存网页资源

          var CACHE_VERSION = 'app-v1';
          var CACHE_FILES = [ ... ];
          
          self.addEventListener('install', function (event) {
              console.log('install', event)
              event.waitUntil(
                  caches.open(CACHE_VERSION)
                      .then(function (cache) {
                          console.log('Opened cache');
                          return cache.addAll(CACHE_FILES);
                      })
              );
          });
      

更新缓存资源

          self.addEventListener('activate', function (event) {
              console.log('activate', event)
              event.waitUntil(
                  caches.keys().then(function (keys) {
                      return Promise.all(keys.map(function (key, i) {
                          if (key !== CACHE_VERSION) {
                              return caches.delete(keys[i]);
                          }
                      }))
                  })
              )
          });
        

监听Fetch事件

          self.addEventListener('fetch', function (event) {
              console.log('fetch', event)
              event.respondWith(
                  caches.match(event.request).then(function (res) {
                      if (res) return res;
                      requestBackend(event);
                  })
              )
          });
          
          function requestBackend (event) {
              console.log('requestBackend', event)
              var url = event.request.clone();
              return fetch(url).then(function (res) {
                  //if not a valid response send the error
                  if (!res || res.status !== 200 || res.type !== 'basic') return res;
          
                  var response = res.clone();
          
                  caches.open(CACHE_VERSION).then(function (cache) {
                      cache.put(event.request, response);
                  });
          
                  return res;
              })
          }
        

推送( Push API )

Push API 让推送服务具备了向 web 应用推送消息的能力;

它定义了 web 应用如何向推送服务发起订阅、如何响应推送消息、web 应用和服务器与推送服务之间的鉴权与加密机制;

由于 Push API 并不依赖 web 应用与浏览器 UI 存活,所以即使是在 web 应用与浏览器未被用户打开的时候,也可以通过后台进程接受推送消息并调用 Notification API 向用户发出通知

通知( Notification API )

负责所有与通知本身相关的机制,如通知权限管理、向操作系统发起通知、通知类型与音效,以及提供通知被点击或关闭时的回调等;

End