使用service worker进行网络瘦身

836 阅读3分钟

基本知识

service worker(sw)

  • 是事件驱动的worker,那么具有web worker特性(如:不能访问DOM;独立于js执行线程等)
  • 充当web应用、浏览器和网络之间的代理,具有缓冲资源、fetch、push、background sync、postMessage等能力
  • 只能运行于https和localhost环境下

sw声明周期

  • installing:发生在sw注册之后,开始安装,触发install事件
  • installed:sw已经安装完了
  • activating:触发activate事件
  • activated:更新缓冲的时机
  • redundant:sw生命周期结束

sw事件

  • install:在该事件回调中可以指定要缓冲的静态资源
  • activate:预处理:更新、清除无用的缓冲
  • message: 可以通过postMessage API与主线程通信
  • fetch:在这一事件中可以处理请求和缓冲(cache first、network first、network only等)
  • push
  • sync

workbox

由于sw借助于cache、indexDB存储资源,而这两个API较复杂,Google推出workbox来解决静态资源和请求结果的本地存储 包括plugin、routing、Strategies以及打包构建插件(如webpack插件workbox-webpack-plugin)

缓冲策略

  • Stale While Revalidate

    1. cache中是否有请求的资源, yes走2,no走3
    2. 将cache结果返回,走3
    3. 发起网络请求,拿到请求结果返回的同时并更新 Cache

    非常安全的策略,能最快拿到请求的结果,但是会有网络请求占用了用户的网络带宽

      ```
      workbox.routing.registerRoute(
          match, // 匹配的路由
          workbox.strategies.staleWhileRevalidate()
      );
      ```
    
  • Network First

    1. 发起网络请求, 成功走2,失败走3
    2. 返回请求结果的同时并更新 cache
    3. 将cache缓冲的结果返回

    适用于返回结果不太固定或对实时性有要求的请求,并对网络异常进行兜底

      ```
      workbox.routing.registerRoute(
          match, // 匹配的路由
          workbox.strategies.networkFirst()
      );
      ```
    
  • Cache First

    1. cache中是否有请求的资源, yes走2,no走3
    2. 将cache结果返回
    3. 发起网络请求,拿到请求结果返回的同时并更新 Cache

    适用于返回结果固定或对实时性要求不高的请求

      ```
      workbox.routing.registerRoute(
          match, // 匹配的路由
          workbox.strategies.cacheFirst()
      );
      ```
    
  • Network Only

    只能使用网络请求,适用于实时性要求很高的请求

    workbox.routing.registerRoute(
        match, // 匹配的路由
        workbox.strategies.networkOnly()
    );
    
  • Cache Only

    直接使用cache缓冲的结果,适用于不会发生变化的静态资源(如:图片)

    workbox.routing.registerRoute(
        match, // 匹配的路由
        workbox.strategies.networkOnly()
    );
    

路由该怎么配置呢?

  • 完整url(如:第三方资源)

    'https://api.map.baidu.com/api?v=3.0&ak=dASz7ubuSpHidP1oQWKuAK3q'
    
  • 正则表达式

    new RegExp('https://maponline[0-9]\\.bdimg\\.com.*/tile/.*')
    
  • 函数

    const matchCb = ({ url }) => {
      return /(statics|js|css)\/(.*)\.(js|css|png|jpg|jpeg|svg|gif)/.test(url)
    }
    
    

如何接入sw

  • webpack配置
const {InjectManifest} = require('workbox-webpack-plugin');

// webpack的plugin中添加
new InjectManifest({
  swDest: 'sw.js',
  swSrc: path.resolve(__dirname, '../sw.js'),
})

  • 注册一个Service Worker
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js');
}
  • 如何编写sw.js
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.0.0-alpha.3/workbox-sw.js');

if (workbox) {
    // 设置cache名和版本
    workbox.core.setCacheNameDetails({
      prefix: 'my-app',
      suffix: 'v1'
    });
    
    // 使当前sw成为activating状态
    workbox.core.skipWaiting()
    
    // 使当前版本的sw在所有的页面中均生效
    workbox.core.clientsClaim()
    
    /**
    定义缓冲策略:
    1. workbox.cacheableResponse:定义资源只有在网络请求成功后才存储
    2. workbox.expiration: 设置一个存储资源的数量和有效期限
    3. cacheName:设置存储与cache中cache名字
    */
    workbox.routing.registerRoute(
        'https://api.map.baidu.com/api?v=3.0&ak=dASz7ubuSpHidP1oQWKuAK3q',
        new workbox.strategies.CacheFirst({
          cacheName: 'baidu',
          plugins: [
            new workbox.cacheableResponse.Plugin({
              statuses: [0, 200],
            }),
            new workbox.expiration.Plugin({
              maxEntries: 20,
              maxAgeSeconds: 7 * 24 * 60 * 60,
            }),
          ],
        })
    )
}

参考

sw生命周期

sw生命周期

sw

sw缓冲策略

workbox使用

借助Service Worker和cacheStorage缓存及离线开发

cacheStorage

workbox常用插件