Service Worker概念和应用介绍

Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理. Service worker是一个注册在指定源和路径下的事件驱动worker。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。

Service worker运行在worker上下文,因此它不能访问DOM。相对于驱动应用的主JavaScript线程,它运行在其他线程中,所以不会造成阻塞。它设计为完全异步,同步API(如XHRlocalStorage)不能在service worker中使用。

出于安全考量,Service workers只能由HTTPS承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险

使用 service worker 步骤

  1. 主进程通过 serviceWorker.register.(子进程service work文件路径)来获取和注册
// js 执行主线程 main.js
navigator.serviceWorker.register('sw.js')
      .then(function(registration) {
        console.log('Registered events at scope: ', registration.scope);
});
  1. 如果注册成功,service worker 就在 ServiceWorkerGlobalScope 环境中运行; 这是一个特殊类型的 woker上下文运行环境,与主运行线程(执行脚本)相独立,同时也没有访问 DOM 的能力。
  2. service worker 现在可以处理事件了。
  3. service worker 控制的页面第一次打开后会尝试去安装 service worker。最先发送给 service worker 的事件是安装事件(在这个事件里可以开始进行填充IndexDB和缓存站点资源)
// sw.js service worker子线程
// self为worker的全局
self.addEventListener('install', function(event) {
  event.waitUntil( // ExtendableEvent.waitUntil() 方法扩展了事件的生命周期。在服务工作线程中,延长事件的寿命从而阻止浏览器在事件中的异步操作完成之前终止服务工作线程。
    caches.open('v1').then(function(cache) { // caches也为service worker内部的全局变量
      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/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});
  1. install 事件的处理程序执行完毕后,ServiceWorker进入installed状态. 这时候主线程中返回的registration.waiting属性代表进入installed状态的ServiceWorker
navigator.serviceWorker.register('./sw.js').then(function(registration) {  
    if (registration.waiting) {
        // Service Worker is Waiting
    }
})
  1. 下一步是激活。当 service worker 安装完成后,如果在之前没有其他的service worker, 该sw会顺理进入下一阶段. 如果之前有service worker, 则该sw会等待一下三种情况.

    • 在新的ServiceWorker线程代码里,使用了self.skipWaiting()
    • 或者当用户导航到别的网页,因此释放了旧的ServiceWorker时候
    • 或者指定的时间过去后,释放了之前的ServiceWorker

    进入下一阶段的时候, 子线程(例子中的sw.js)会接收到一个激活事件(activate event)。 activating阶段主要用途是清理先前版本的service worker 脚本中使用的资源。

const cacheStorageKey = '该版本指定资源'
self.addEventListener('activate', function(e) {
  // active事件中通常做一些过期资源释放的工作
  var cacheDeletePromises = caches.keys().then(cacheNames => {
    console.log('cacheNames', cacheNames, cacheNames.map);
    return Promise.all(cacheNames.map(name => {
      if (name !== cacheStorageKey) { // 如果资源的key与当前需要缓存的key不同则释放资源
        console.log('caches.delete', caches.delete);
        var deletePromise = caches.delete(name);
        console.log('cache delete result: ', deletePromise);
        return deletePromise;
      } else {
        return Promise.resolve();
      }
    }));
  });

  console.log('cacheDeletePromises: ', cacheDeletePromises);
  e.waitUntil(
    Promise.all([cacheDeletePromises]
    )
  )
})

e.waitUntil接收的Promise进入成功状态后,ServiceWorker的生命周期则进入activated状态。这个时候主线程中的registrationactive属性代表进入activated状态的ServiceWorker实例

navigator.serviceWorker.register('./sw.js').then(function(registration) {  
    if (registration.active) {
        // Service Worker is Active
    }
})
  1. Service Worker 现在可以控制页面了,这时候就可以做一些请求拦截的操作
self.addEventListener('fetch', function(event) {
  event.respondWith(
  //  caches.match()返回的总是resolves状态, 但如果匹配到之前的请求返回的会有值, 找不到返回undefined

    caches.match(event.request).then(function() {
      return fetch(event.request).then(function(response) {
        return caches.open('v1').then(function(cache) {
          cache.put(event.request, response.clone()); // 放入缓存中
          // clone 原因: 请求和响应流只能被读取一次。为了给浏览器返回响应以及把它缓存起来,我们不得不克隆一份。所以原始的会返回给浏览器,克隆的会发送到缓存中。它们都是读取了一次。
          return response;
        });  
      });
    }).catch(function() {
      return caches.match('/sw-test/gallery/myLittleVader.jpg');
    })
  );
});

参考链接:

https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers

https://www.cnblogs.com/dojo-lzz/p/8047336.htm

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值