当前位置: 首页 > news >正文

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 ageentries.sort((a, b) => a.url < b.url ? 1 : -1);// Delete old or excess entriesfor(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 hitreturn response;}// Cache missreturn 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的原生使用,两者其实可以根据业务需要去并存

http://www.lryc.cn/news/102957.html

相关文章:

  • 秋招算法备战第32天 | 122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II
  • Python状态模式介绍、使用
  • Github-Copilot初体验-Pycharm插件的安装与测试
  • Spring AOP API详解
  • 分治法 Divide and Conquer
  • super(Module_ModuleList, self).__init__()的作用是什么?
  • 【并发专题】操作系统模型及三级缓存架构
  • java基础复习(第二日)
  • Ansible自动化运维工具
  • LeetCode-116-填充每个节点的下一个右侧节点指针
  • 前端面试的性能优化部分(3)每篇10题
  • 如何通过企业工商信息初步判断企业是否靠谱?
  • ChatGPT+知乎,20分钟超越专业大V的调教方法
  • git branch --show-current 和 git rev-parse --abbrev-ref HEAD 区别
  • 【TypeScript】接口类型 Interfaces 的使用理解
  • 2023-07-31 C语言根据错误号打印详细的错误信息perror(““) 或者strerror(errno)
  • JDK17和JDK8完美卸载方法及新版JDK安装教程
  • FPGA设计时序分析二、建立/恢复时间
  • oracle建立自动增长字段
  • 【Git】远程仓库的创建、SSH协议克隆、拉取、推送
  • C#之泛型
  • Scrum敏捷开发管理流程+scrum工具免费
  • 【操作系统基础】Linux 中 /var/log/ 文件夹下通常有哪一些文件?分别的作用是什么?
  • 【构造】CF1758 C
  • 【etcd】docker 启动单点 etcd
  • 【单链表OJ题:反转链表】
  • Unity UGUI的LayoutRebuilder的介绍及使用
  • 深刻理解python特性-列表推导式和生成器表达式
  • Sentinel dashboard的使用;Nacos保存Sentinel限流规则
  • vue学习之插值表达式{{}}与显示数据(v-text和v-html)