Workbox使用分享

一、简要介绍

1.1 什么是Workbox

官方文档原文:

At this point, service workers may seem tricky. There’s lots of complex interactions that are hard to get right. Network requests! Caching strategies! Cache management! Precaching! It’s a lot to remember. This doesn’t make service worker an ill-designed technology; it works as intended, and solves hard problems.

Good abstractions make complex APIs easier to use. That’s where Workbox comes in. Workbox is a set of modules that simplify common service worker routing and caching. Each module available addresses a specific aspect of service worker development. Workbox aims to make using service workers as easy as possible, while allowing the flexibility to accommodate complex application requirements where needed.

官方介绍文档链接:What is Workbox?

简单的来说 Workbox 是由 Google 开发的一个基于 Service Worker 的js库,提供了很多高效好用的工具和策略,其目的在于更加高效的实现应用缓存和离线优先应用(PWA),不再需要繁杂的编写SW相关的代码

1.2 Workbox的主要特性

  1. Runtime Caching(运行时缓存):
    • Workbox 提供了多种灵活的运行时缓存策略,以缓存动态内容,如 API 响应。
    • 内置的策略包括 NetworkFirst(优先从网络获取)、CacheFirst(优先从缓存获取)、StaleWhileRevalidate(边缘过期时刷新)等。
    • 开发者可以根据应用程序的需求选择适当的策略,并灵活配置缓存行为。
  2. Strategies and Routing(策略和路由):
    • Workbox 提供了灵活的路由和处理网络请求的能力,开发者可以根据具体需求定义自定义的缓存策略和路由规则。
    • 这使得开发者可以根据特定的 URL、请求方法或其他条件来定义不同的缓存行为,以满足应用程序的特定需求。
  3. Precaching(预缓存):
    • Workbox 允许开发者在服务工作者安装阶段预缓存静态资源,包括 HTML、CSS、JavaScript 文件、图像等。
    • 预缓存的资源在离线状态下可用,提高应用程序的可靠性和性能。
  4. Background Sync(后台同步):
    • Workbox 简化了实现后台同步的过程,允许将失败的网络请求排队并在用户恢复网络连接时重新尝试发送。
    • 后台同步功能可以提高应用程序的可靠性,确保关键操作(如提交表单或数据同步)在离线状态下也能正常完成。

1.3 如何在SW文件中使用

推荐在SW文件中引入Workbox cdn使用

importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');

二、具体使用

2.1 请求策略

在使用 Workbox 之前先然我们了解一下其提供的几种常用缓存策略

tips: 此处只介绍了业务中比较能用到的策略,像 Cache only(仅使用缓存)等不大可能使用的策略就不在这里展开了

CacheFirst(优先从缓存获取)

该策略将在页面发出请求时优先使用缓存中的数据作为响应,在缓存中无响应时才会发起网络请求

这种策略适合缓存一些不经常变动的资源,例如在 hoyolab 主站 pc 中使用了这种策略缓存了图片与svga等静态资源

NetworkFirst(优先从网络获取)

该策略将在页面发出请求时优先进行网络请求,请求成功后将响应存至缓存,当请求失败,若缓存中有内容响应则使用缓存响应

这种策略适合对稳定性要求较高的业务场景,保证在服务器错误时,前端应用不至于完全不可用

StaleWhileRevalidate(先从缓存获取,同时向网络请求)

该策略将在页面发出请求时先尝试使用缓存作为响应,然后在后台发起网络请求,将请求的响应更新至缓存,当然若缓存一开始就响应失败则直接使用网络请求

这种策略适合有变动的需求,但能接受当前使用过期缓存,后续访问更新的场景,或是对一些第三方资源的缓存

例如在 hoyolab 主站 pc 业务中就使用了该种策略缓存了语言列表、编辑器分割线资源、第三方播放器脚本(YouTube, twitch),多语言资源等请求

2.2 运行时缓存

运行时缓存 Runtime Caching 支持我们更加灵活和动态的去指定我们的缓存方案,我们可以指定一些路由来配置相应的缓存策略,来捕获一些动态内容,根据我们的策略来做缓存

使用方式

workbox.routing.registerRoute(matchCallback, handlerCallback, method)
参数作用
matchCallback可以是一个函数或者正则表达式用来匹配请求路由
handlerCallback处理匹配请求的策略函数,一般而言直接使用 Workbox 提供的策略new workbox.strategies[‘策略’]
method(可选)请求方法POST/GET若未指定则会默认匹配所有http方法

以下是运行时缓存的代码示例

workbox.routing.registerRoute(
    new RegExp('\\.(?:svg|svga)$'), // 路由匹配正则
    new workbox.strategies.CacheFirst({ // 上文提到的缓存策略
        cacheName: 'svgCache', // 可以为你的缓存起个自定义名字方便后续的管理
        plugins: [
            new workbox.expiration.ExpirationPlugin({
                maxEntries: 50, // 设置最大请求条数
                maxAgeSeconds: 7 * 24 * 60 * 60, // 设置最长请求时间7天
            }),
        ],
    })
);

2.3 预缓存

预缓存是在SW安装的阶段就根据指定的缓存列表将资源存至缓存中,使其在离线状态下也可以进行访问

使用方式

workbox.precaching.precacheAndRoute(cacheArr)

该方法接受一个数组,我们可以在数组中指定我们想要缓存的资源

workbox.precaching.precacheAndRoute([
  {url: '/A.html', revision: '1.0.0' },
  {url: '/B.css', revision: '1.0.0'},
  {url: '/C.js', revision: '1.0.0'}
]);

revision字段主要用于标识我们的缓存版本,当改标识变更时会触发缓存更新

当然提供workbox的一些工具和构建流程结合我们也可以将这个过程自动化,这里先不展开了

2.4 后台同步

后台同步允许你在某个时机或周期性的在后台对后端数据进行同步

比如用户请求了数据,但是当前网络环境不稳定导致用户离线,这时我们可以使用 workbox 将失败的请求收集起来,在用户网络环境恢复时再次请求

下面是一个简单的实例

注册待重试的请求

const bgSyncPlugin = new workbox.backgroundSync.BackgroundSyncPlugin('retryQueue', {
  maxRetentionTime: 24 * 60 // 最多重试时间
});

workbox.routing.registerRoute(
  /\/api/, // 随便写了个正则
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin]
  }),
  'POST'
);

该实例中我们设置了一个同步队列 retryQueue,然后匹配所有的/api请求,在这些请求失败时将请求加入到我们的重试队列中

注册待执行的函数

workbox.backgroundSync.registerRoute('retryQueue', async ({queue}) => {
  let entry;
  while (entry = await queue.shiftRequest()) {
    try {
      const response = await fetch(entry.request);
      const responseData = await response.json();
    } catch (error) {
      await queue.unshiftRequest(entry);
      return;
    }
  }
});

该实例函数会在用户重新在线时触发,从 retryQueue 队列中取出请求并执行,请求成功我们可以同步这些数据到业务侧,若请求失败则放回请求队列

除此之外SW的后台同步还能有更多的使用方式如表单后台同步,备份,轮询状态等场景这里就不展开了

三、为什么更倾向与使用Workbox,直接使用原生SW不好吗?

其实就正如介绍中所说的Workbox基于SW提供了非常多的工具和实现,简化了SW的使用,开发者能使用workbox更快的实现业务上的缓存功能,而不必编写底层的缓存策略

比如前文介绍的对svg资源的缓存,我们可以对比一下原生SW与workbox的实现差异

workbox:

workbox.routing.registerRoute(
    new RegExp('\\.(?:svg|svga)$'), // 路由匹配正则
    new workbox.strategies.CacheFirst({ // 上文提到的缓存策略
        cacheName: 'svgCache', // 可以为你的缓存起个自定义名字方便后续的管理
        plugins: [
            new workbox.expiration.ExpirationPlugin({
                maxEntries: 50, // 设置最大请求条数
                maxAgeSeconds: 7 * 24 * 60 * 60, // 设置最长请求时间7天
            }),
        ],
    })
);

SW原生实现demo(生产环境策略指定需要更加的细化)

const CACHE_NAME = 'svga-cache';
const MAX_ENTRIES = 50;
const MAX_AGE = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds

// Clean old cache entries
async function cleanCache() {
  const cache = await caches.open(CACHE_NAME);
  const keys = await cache.keys();
  const entries = keys.filter(request => request.url.endsWith('.svga'));
  
  // Sort entries by age
  entries.sort((a, b) => a.url < b.url ? 1 : -1);
  
  // Delete old or excess entries
  for(let i = entries.length - 1; i >= 0; i--) {
    if(i > MAX_ENTRIES - 1 || (Date.now() - entries[i].url) > MAX_AGE) {
      await cache.delete(entries[i]);
    }
  }
}

// Install event
self.addEventListener('install', event => {
  event.waitUntil(cleanCache());
});

// Fetch event
self.addEventListener('fetch', event => {
  if (event.request.url.endsWith('.svga')) {
    event.respondWith(caches.open(CACHE_NAME).then(cache => {
      return cache.match(event.request).then(response => {
        if (response) {
          // Cache hit
          return response;
        }
        
        // Cache miss
        return fetch(event.request.clone()).then(networkResponse => {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        });
      });
    }));
  }
});

// Activate event
self.addEventListener('activate', event => {
  event.waitUntil(cleanCache());
});

很容易看出workbox具备更强大的易用性

当然选择workbox也并不是完全抛弃SW的原生使用,两者其实可以根据业务需要去并存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值