1.介绍

​ PWA应用是指那些使用指定技术和标准模式来开发的web应用,这将同时赋予它们web应用和原生应用的特性。例如:

  • Discoverable, 内容可以通过搜索引擎发现。

  • Installable, 可以出现在设备的主屏幕。

  • Linkable, 你可以简单地通过一个URL来分享它。

  • Network independent, 它可以在离线状态或者是在网速很差的情况下运行。

  • Progressive, 它在老版本的浏览器仍旧可以使用,在新版本的浏览器上可以使用全部功能。

  • Re-engageable, 无论何时有新的内容它都可以发送通知。

  • Responsive, 它在任何具有屏幕和浏览器的设备上可以正常使用——包括手机,平板电脑,笔记本,电视,冰箱,等。

  • Safe, 在你和应用之间的连接是安全的,可以阻止第三方访问你的敏感数据。

2. demo

service worker能劫持所有的网络请求,安全原因必须要在https或者localhost下运行。以下是一个项目地址为 https://mdn.github.io/sw-test 的例子,步骤如下:

2.1 注册

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' })
  .then(function(reg) {
    // registration worked
    console.log('Registration succeeded. Scope is ' + reg.scope);
  })
  .catch(function(error) {
    // registration failed
    console.log('Registration failed with ' + error);
  });
}

该段代码检测是否支持serviceWorker,支持的话注册/sw-test/sw.js(url 是相对于域名),scope选填,表示service worker影响范围(该范围不能比注册的地方大,在该例子中,最大就是/sw-test/。除非后端设置了Service-Worker-Allowed),默认是当前路径(https://mdn.github.io/sw-test)

2.2 安装

Sw.js中完成具体逻辑,如下:

this.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});
  • Event.waitUntil确保Service Worker 不会在 waitUntil() 里面的代码执行完毕之前安装完成。
  • caches.open() 方法来创建了一个叫做 v1 的新的缓存
  • addAll()这个方法的参数是一个由一组相对于 origin 的 URL 组成的数组,这些 URL 就是你想缓存的资源的列表,他会马上去加载一次这些资源,并且缓存。

当promise被reject的时候,安装失败,反之安装成功,service worker就会激活。

2.3 劫持

每次任何被 service worker 控制的资源被请求到时,都会触发 fetch 事件,这些资源包括了指定的 scope 内的文档,和这些文档内引用的其他任何资源(比如 index.html 发起了一个跨域的请求来嵌入一个图片,这个也会通过 service worker 。)

this.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
  );
});

以上例子只是简单的响应这些缓存中的 url 和网络请求匹配的资源。

3. 生命周期

  • Installing

    安装sw,执行install钩子。可以进行一些资源缓存,数据初始化(indexedDB)

  • installed

    已经安装完成,等待使用了旧版本的sw的页面关闭

  • activating

    激活sw,执行active钩子

  • activate

    激活成功之后才能开始管控页面,fetch这些钩子才开始有效

  • redundant

    失败获取被其他sw取代

4. 更新顺序

  1. 页面上通过navigator.serviceWorker.register来获取和注册。

  2. 受 service worker 控制的页面打开后会尝试去安装 service worker。最先发送给 service worker 的事件是安装事件(在这个事件里可以开始进行填充 IndexDB和缓存站点资源)。这个流程同原生 APP 或者 Firefox OS APP 是一样的 — 让所有资源可离线访问。

  3. oninstall事件的处理程序执行完毕后,可以认为 service worker 安装完成了。

  4. 下一步是激活。当 service worker 安装完成后,会接收到一个激活事件(activate event)。 onactivate主要用途是清理先前版本的service worker 脚本中使用的资源。

  5. 重新刷新页面,会检测sw.js有无变化。没变化,不会重新在浏览器注册一个新的service worker(install钩子不会执行),还是用旧的;有变化,会重新注册一个sw。期间,install钩子会直接执行,但是activate和其他不会执行,所以一般在activate清空上个版本的service worker相关缓存,等待使用旧的sevice worker的页面都关闭后,再激活新的service worker(如果使用了skipWaiting函数即可直接跳过install阶段)。未激活的service worker谷歌显示如下:

    image-20200527163404854

    下次再打开页面的时候,同时触发install和activate钩子

  6. Service Worker 现在可以控制页面了,但仅是在 register() 成功后的打开的页面。也就是说,页面起始于有或则没有 service worker ,且在页面的接下来生命周期内维持这个状态。所以,页面不得不重新加载以让 service worker 获得完全的控制。(在activate钩子里使用clients.claim可以立即接管页面)

5. 注意事项

5.1 全局变量

service worker运行在浏览器独立的线程,因此没有获取dom的权限。单个 service worker 可以控制很多页面。每个你的 scope 里的页面加载完的时候,安装在页面的 service worker 可以控制它。牢记你需要小心 service worker 脚本里的全局变量: 每个页面不会有自己独有的worker。

5.2 部分对象不可用

如window、localStorage、XMLHttpRequest在sw的上下文里是undefined,不确定的api用之前先测试一下。

5.3 域名

只能在https和localhost里面使用service worker,本地测试的时候请使用localhost(127.0.0.1实测也行),用其他ip都不行,’serviceWorker’ in navigator会返回false

5.4 不要更改service worker文件名

启用离线访问的情况下,首页(index.html)会被sw(service worker)缓存。如果sw文件名称修改了,因为首页被缓存了,注册的sw文件路径还是旧的,所以根本不会启用新的sw(找不到sw文件并不会删除或更新sw)。

5.5 调试

由于service worker独立存在,所以错误的service worker可能会导致页面不可访问等其他情况。可以先去application选项卡把service worker清除

image-20200527151840562

6.各api兼容性

和service worker配套使用的api支持情况和service worker本身不一致,支持情况如下

6.1 serviceWorker

image-20200528190447870

6.2 caches

caches对象mdn介绍。有match、 has、open、delete和keys四个函数,都是返回promise。兼容如下图

image-20200527134243932

6.3 fetch

image-20200527144635398

6.4 结论

直接service worker的就一定支持cache和fetch(2,3项功能不行),所以用如下代码即可:

if ('serviceWorker' in navigator) {
      console.log('支持service worker')
      navigator.serviceWorker.register('<%= process.env.VUE_APP_PWA_PATH %>service-worker.js')
      .then(function(reg) {
        // registration worked
        console.log('Registration succeeded. Scope is ' + reg.scope);
      })
      .catch(function(error) {
        // registration failed
        console.log('Registration failed with ' + error);
      });
    } else {
      console.log('不支持service worker')
    }

7.手机实测

安卓app(x5): 支持navigator.serviceWorker属性, 但是install钩子不执行,原因未明

安卓app:image-20200601105517390

安卓自带浏览器: 正常。由于连手机无法正常查看浏览器相关cache。接口时间对比如下(http和https):

image-20200531133132867

image-20200531133427630

Ios safari:

image-20200531134333522
image-20200531134333522

iOS app:不支持。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

Google V8引擎学习笔记(一) 上一篇
不使用 brew,如何安装 zsh ? 下一篇