React 前端导航

workbox 怎么使用

workbox 怎么使用

由于直接写原生的 sw.js,比较繁琐和复杂,所以一些工具就出现了,而 workbox 是其中的佼佼者,由 google 团队推出。

简介

在 Workbox 之前,GoogleChrome 团队较早时间推出过 sw-precache 和 sw-toolbox 库,但是在 GoogleChrome 工程师们看来,workbox 才是真正能方便统一的处理离线能力的更完美的方案,所以停止了对 sw-precache 和 sw-toolbox 的维护。

基本配置

首先,需要在项目的 sw.js 文件中,引入 workbox 的官方 js,这里用了我们自己的静态资源:

importScripts(
    "https://edu-cms.nosdn.127.net/topics/js/workbox_9cc4c3d662a4266fe6691d0d5d83f4dc.js"
);

其中 importScripts 是 webworker 中加载 js 的方式。
引入 workbox 后,全局会挂载一个 workbox 对象

if (workbox) {
    console.log('workbox加载成功');
} else {
    console.log('workbox加载失败');
}

然后需要在使用其他的 api 前,提前使用配置

//关闭控制台中的输出
workbox.setConfig({ debug: false });

也可以统一指定存储时 cache 的名称:

//设置缓存cachestorage的名称
workbox.core.setCacheNameDetails({
    prefix:'edu-cms',
    suffix:'v1'
});

precache

workbox 的缓存分为两种,一种的 precache,一种的 runtimecache。

precache 对应的是在 installing 阶段进行读取缓存的操作。它让开发人员可以确定缓存文件的时间和长度,以及在不进入网络的情况下将其提供给浏览器,这意味着它可以用于创建 Web 离线工作的应用。

工作原理

首次加载 Web 应用程序时,workbox 会下载指定的资源,并存储具体内容和相关修订的信息在 indexedDB 中。
当资源内容和 sw.js 更新后,workbox 会去比对资源,然后将新的资源存入 cache,并修改 indexedDB 中的版本信息。

举一个例子:

service worker workbox

indexedDB 中会保存其相关信息
service worker workbox

这个时候我们把 main.css 的内容改变后,再刷新页面,会发现除非强制刷新,否则 workbox 还是会读取 cache 中存在的老的 main.css 内容。
即使我们把 main.css 从服务器上删除,也不会对页面造成影响。
所以这种方式的缓存都需要配置一个版本号。在修改 sw.js 时,对应的版本也需要变更。

使用实践

当然了,一般我们的一些不经常变的资源,都会使用 cdn,所以这里自然就需要支持域外资源了,配置方式如下:

var fileList = [
    {
        url:'https://edu-cms.nosdn.127.net/topics/js/cms_specialWebCommon_js_f26c710bd7cd055a64b67456192ed32a.js'
    },
    {
        url:'https://static.ws.126.net/163/frontend/share/css/article.207ac19ad70fd0e54d4a.css'
    }
];

//precache 适用于支持跨域的cdn和域内静态资源
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(fileList, {
    "ignoreUrlParametersMatching": [/./]
});

这里需要对应的资源配置跨域允许头,否则是不能正常加载的。且文件都要以版本文件名的方式,来确保修改后 cache 和 indexDB 会得到更新。
理解了原理和实践后,说明这种方式适合于上线后就不会经常变动的静态资源。

runtimecache

运行时缓存是在 install 之后,activated 和 fetch 阶段做的事情。
既然在 fetch 阶段发送,那么 runtimecache 往往应对着各种类型的资源,对于不同类型的资源往往也有不同的缓存策略。

缓存策略

workbox 提供的缓存策划有以下几种,通过不同的配置可以针对自己的业务达到不同的效果:

1.staleWhileRevalidate

这种策略的意思是当请求的路由有对应的 Cache 缓存结果就直接返回,
在返回 Cache 缓存结果的同时会在后台发起网络请求拿到请求结果并更新 Cache 缓存,如果本来就没有 Cache 缓存的话,直接就发起网络请求并返回结果,这对用户来说是一种非常安全的策略,能保证用户最快速的拿到请求的结果。

但是也有一定的缺点,就是还是会有网络请求占用了用户的网络带宽。可以像如下的方式使用 State While Revalidate 策略:

workbox.routing.registerRoute(
    new RegExp('https://edu-cms\.nosdn\.127\.net/topics/'),
    workbox.strategies.staleWhileRevalidate({
        //cache名称
        cacheName: 'lf-sw:static',
        plugins: [
            new workbox.expiration.Plugin({
                //cache最大数量
                maxEntries: 30
            })
        ]
    })
);
2.networkFirst

这种策略就是当请求路由是被匹配的,就采用网络优先的策略,也就是优先尝试拿到网络请求的返回结果,如果拿到网络请求的结果,就将结果返回给客户端并且写入 Cache 缓存。

如果网络请求失败,那最后被缓存的 Cache 缓存结果就会被返回到客户端,这种策略一般适用于返回结果不太固定或对实时性有要求的请求,为网络请求失败进行兜底。可以像如下方式使用 Network First 策略:

//自定义要缓存的html列表
var cacheList = [
    '/Hexo/public/demo/PWADemo/workbox/index.html'
];
workbox.routing.registerRoute(
    //自定义过滤方法
    function(event) {
        // 需要缓存的HTML路径列表
        if (event.url.host === 'localhost:63342') {
            if (~cacheList.indexOf(event.url.pathname)) return true;
            else return false;
        } else {
            return false;
        }
    },
    workbox.strategies.networkFirst({
        cacheName: 'lf-sw:html',
        plugins: [
            new workbox.expiration.Plugin({
                maxEntries: 10
            })
        ]
    })
);
3.cacheFirst

这个策略的意思就是当匹配到请求之后直接从 Cache 缓存中取得结果,如果 Cache 缓存中没有结果,那就会发起网络请求,拿到网络请求结果并将结果更新至 Cache 缓存,并将结果返回给客户端。这种策略比较适合结果不怎么变动且对实时性要求不高的请求。可以像如下方式使用 Cache First 策略:

workbox.routing.registerRoute(
    new RegExp('https://edu-image\.nosdn\.127\.net/'),
    workbox.strategies.cacheFirst({
        cacheName: 'lf-sw:img',
        plugins: [
            //如果要拿到域外的资源,必须配置
            //因为跨域使用fetch配置了
            //mode: 'no-cors',所以status返回值为0,故而需要兼容
            new workbox.cacheableResponse.Plugin({
                statuses: [0, 200]
            }),
            new workbox.expiration.Plugin({
                maxEntries: 40,
                //缓存的时间
                maxAgeSeconds: 12 * 60 * 60
            })
        ]
    })
);
4.networkOnly

比较直接的策略,直接强制使用正常的网络请求,并将结果返回给客户端,这种策略比较适合对实时性要求非常高的请求。

5.cacheOnly

这个策略也比较直接,直接使用 Cache 缓存的结果,并将结果返回给客户端,这种策略比较适合一上线就不会变的静态资源请求。

举个例子

又到了举个栗子的阶段了,这次我们用淘宝好了,看看他们是如何通过 workbox 来配置 serviceworker 的:

//首先是异常处理
self.addEventListener('error', function(e) {
  self.clients.matchAll()
    .then(function (clients) {
      if (clients && clients.length) {
        clients[0].postMessage({
          type: 'ERROR',
          msg: e.message || null,
          stack: e.error ? e.error.stack : null
        });
      }
    });
});

self.addEventListener('unhandledrejection', function(e) {
  self.clients.matchAll()
    .then(function (clients) {
      if (clients && clients.length) {
        clients[0].postMessage({
          type: 'REJECTION',
          msg: e.reason ? e.reason.message : null,
          stack: e.reason ? e.reason.stack : null
        });
      }
    });
})
//然后引入workbox
importScripts('https://g.alicdn.com/kg/workbox/3.3.0/workbox-sw.js');
workbox.setConfig({
  debug: false,
  modulePathPrefix: 'https://g.alicdn.com/kg/workbox/3.3.0/'
});
//直接激活跳过等待阶段
workbox.skipWaiting();
workbox.clientsClaim();
//定义要缓存的html
var cacheList = [
  '/',
  '/tbhome/home-2017',
  '/tbhome/page/market-list'
];
//html采用networkFirst策略,支持离线也能大体访问
workbox.routing.registerRoute(
  function(event) {
    // 需要缓存的HTML路径列表
    if (event.url.host === 'www.taobao.com') {
      if (~cacheList.indexOf(event.url.pathname)) return true;
      else return false;
    } else {
      return false;
    }
  },
  workbox.strategies.networkFirst({
    cacheName: 'tbh:html',
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 10
      })
    ]
  })
);
//静态资源采用staleWhileRevalidate策略,安全可靠
workbox.routing.registerRoute(
  new RegExp('https://g\.alicdn\.com/'),
  workbox.strategies.staleWhileRevalidate({
    cacheName: 'tbh:static',
    plugins: [
      new workbox.expiration.Plugin({
        maxEntries: 20
      })
    ]
  })
);
//图片采用cacheFirst策略,提升速度
workbox.routing.registerRoute(
  new RegExp('https://img\.alicdn\.com/'),
  workbox.strategies.cacheFirst({
    cacheName: 'tbh:img',
    plugins: [
      new workbox.cacheableResponse.Plugin({
        statuses: [0, 200]
      }),
      new workbox.expiration.Plugin({
        maxEntries: 20,
        maxAgeSeconds: 12 * 60 * 60
      })
    ]
  })
);

workbox.routing.registerRoute(
  new RegExp('https://gtms01\.alicdn\.com/'),
  workbox.strategies.cacheFirst({
    cacheName: 'tbh:img',
    plugins: [
      new workbox.cacheableResponse.Plugin({
        statuses: [0, 200]
      }),
      new workbox.expiration.Plugin({
        maxEntries: 30,
        maxAgeSeconds: 12 * 60 * 60
      })
    ]
  })
);

可以看出,使用 workbox 比起直接手撸来,要快很多,也明确很多。

声明:本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。邮箱:farmerlzj@163.com。 本站原创内容未经允许不得转载,或转载时需注明出处: 内容转载自: React前端网:https://qianduan.shop/blogs/detail/85

#js#service worker#缓存#workbox

相关推荐

原型与原型链、继承

原型与原型链、继承简单实现

浏览器中的js事件循环(Event loop)

本文将简述浏览器中的js事件循环机制,帮助我们理解浏览器环境js代码是如何运行的。Javascript的一大特点是单线程,也就意味着同一时间他只能做一件事。事件循环(Event Loop)是为了协调事件,用户交互,UI渲染,网络处理等行为,防止线程阻塞而诞生的。