PWA缓存策略区别NetworkOnly/CacheFirst/CacheOnly/NetworkFirst/StaleWhileRevalidate

现在来看看 Workbox 提供的缓存策略,主要有这几种:

cache-first,

cache-only,

network-first,

network-only,

stale-while-revalidate

在前面看到,实例化的时候会给 workbox 挂载一个 Strategies 的实例。提供上面一系列的缓存策略,但在实际调用中,使用的是 _getCachingMechanism,然后把整个策略类放到一参中,二参则提供了配置项,在每个策略类中都有 handle 方法的实现,最终也会调用 handle方法。那既然如此还搞个 _getCachingMechanism干嘛,直接返回策略类就得了,这个等下看。

先看下各个策略,这里就简单说下,可以参考离线指南,虽然会有一点不一样。

Cache-First

第一个 Cache-First, 它的 handle 方法:

const cachedResponse = await this.requestWrapper.match({request: event.request,
});return cachedResponse || await this.requestWrapper.fetchAndCache({request: event.request,waitOnCache: this.waitOnCache,
});

Cache-First策略会在有缓存的时候返回缓存,没有缓存才会去请求并且把请求结果缓存,这也是我们对于precache的策略。

Cache-only

然后是 Cache-only,它只会去缓存里拿数据,没有就失败了。

network-first

network-first 是一个比较复杂的策略,它接受 networkTimeoutSeconds 参数,如果没有传这个参数,请求将会发出,成功的话就返回结果添加到缓存中,如果失败则返回立即缓存。这种网络回退到缓存的方式虽然利于那些频繁更新的资源,但是在网络情况比较差的情况(无网会直接返回缓存)下,等待会比较久,这时候 networkTimeoutSeconds 就提供了作用,如果设置了,会生成一个setTimeout后被resolve的缓存调用,再把它和请求放倒一个 Promise.race 中,那么请求超时后就会返回缓存。

network-only

network-only,也比较简单,只请求,不读写缓存。

StaleWhileRevalidate

最后提供的策略是 StaleWhileRevalidate,这种策略比较接近 cache-first,代码如下:

const fetchAndCacheResponse = this.requestWrapper.fetchAndCache({request: event.request,waitOnCache: this.waitOnCache,cacheResponsePlugin: this._cacheablePlugin,
}).catch(() => Response.error());const cachedResponse = await this.requestWrapper.match({request: event.request,
});return cachedResponse || await fetchAndCacheResponse;

他们的区别在于就算有缓存,它仍然会发出请求,请求的结果会用来更新缓存,也就是说你的下一次访问的如果时间足够请求返回的话,你就能拿到最新的数据了。

可以看到离线指南中还提供了缓存然后访问网络再更新页面的方法,但这种需要配合主进程代码的修改,WorkBox 没有提供这种模式。

自定义缓存配置

回到在缓存策略里提到的,讲讲 _getCachingMechanism和缓存策略的参数。默认支持5个参数:'cacheExpiration', 'broadcastCacheUpdate', 'cacheableResponse', 'cacheName', 'plugins',(当然你会发现还有几个参数不在这里处理,比如你可以传一个自定义的 requestWrapper, 前面提到的 waitOnCache 和 NetworkFirst 支持的 networkTimeoutSeconds),先看一个完整的示例:

const workboxSW = new WorkboxSW();
const cacheFirstStrategy = workboxSW.strategies.cacheFirst({cacheName: 'example-cache',cacheExpiration: {maxEntries: 10,maxAgeSeconds: 7 * 24 * 60 * 60},broadcastCacheUpdate: {channelName: 'example-channel-name'},cacheableResponse: {stses: [0, 200, 404],headers: {'Example-Header-1': 'Header-Value-1','Example-Header-2': 'Header-Value-2'}}plugins: [// Additional Plugins]
});

大致可以认定的是 cacheExpiration 会用来处理缓存失效,cacheName 决定了 cache 的索引名,cacheableResponse 则决定了什么请求返回可以被缓存。

那么插件到底是怎么被处理,现在可以看_getCachingMechanism函数了,_getCachingMechanism函数处理了什么,它其实就是把 cacheExpirationbroadcastCacheUpdate,cacheabelResponse里的参数找到对应方法,传入参数实例化,然后挂在在封装后的wrapperOptions的plugins参数里,但是只是实例化了有什么用呢?这里有关键的一步:

options.requestWrapper = new RequestWrapper(wrapperOptions);

所以最终这些插件还是会在 RequestWrapper 里处理,这里的一些操作是我们之前没有提到的,来看下 RequestWrapper 里怎么处理的。

看下 RequestWrapper 的构造函数,取其中涉及到 plugins 的部分:

constructor({cacheName, cacheId, plugins, fetchOptions, matchOptions} = {}) {this.plugins = new Map();if (plugins) {isArrayOfType({plugins}, 'object');plugins.forEach((plugin) => {for (let callbackName of pluginCallbacks) {if (typeof plugin[callbackName] === 'function') {if (!this.plugins.has(callbackName)) {this.plugins.set(callbackName, []);} else if (callbackName === 'cacheWillUpdate') {throw ErrorFactory.createError('multiple-cache-will-update-plugins');} else if (callbackName === 'cachedResponseWillBeUsed') {throw ErrorFactory.createError('multiple-cached-response-will-be-used-plugins');}this.plugins.get(callbackName).push(plugin);}}});}
}

plugins是一个Map,默认支持以下几种Key:cacheDidUpdatecacheWillUpdatefetchDidFailrequestWillFetchcachedResponseWillBeUsed。可以理解为 requestWrapper 提供了一些hooks或者生命周期,而插件就是在 hook 上进行一些处理。

这里举个缓存失效的例子看看怎么处理:

首先我们需要实例化CacheExpirationPlugin,CacheExpirationPlugin没有构造函数,实例化的是CacheExpiration,然后在this上添加maxEntries,maxAgeSeconds。所有的 hook 方法实现都放在了 CacheExpirationPlugin,提供了两个 hook: cachedResponseWillBeUsed 和 cacheDidUpdate,cachedResponseWillBeUsed 会在 RequestWrapper的match中执行,cacheDidUpdate 在 fetchAndCache中 执行。

这里可以看出,每个plugin其实就是对hook或者生命周期调用的具体实现,在把response扔到cache里之后,调用了插件的cacheDidUpdate方法,看下CacheExpirationPlugin中的cacheDidUpdate:

async cacheDidUpdate({cacheName, newResponse, url, now} = {}) {isType({cacheName}, 'string');isInstance({newResponse}, Response);if (typeof now === 'undefined') {now = Date.now();}await this.updateTimestamp({cacheName, url, now});await this.expireEntries({cacheName, now});
}

那么关键就是更新时间戳和失效条数,如果设置了更新时间戳会怎么样呢,在请求的时候,runtimecache也会添加到IndexedDB,值存入的是一个对象,包含了一个url和时间戳。

这个时间戳怎么生效,CacheExpirationPlugin提供了另外一个方法,cachedResponseWillBeUsed:

cachedResponseWillBeUsed({cachedResponse, cachedResponse, now} = {}) {if (this.isResponseFresh({cachedResponse, now})) {return cachedResponse;}return null;
}

RequestWrapper中的match方法会默认从cache里取,取到的是当时的完整 response, 在cache的 response 里的 headers 里取到 date,然后把当时的date加上 maxAgeSecond 和 现在的时间比, 如果小于了就返回 false,那么自然会去发起请求了。

CacheableResponsePlugin用来控制 fetchAndCache 里的 cacheable,它设置了一个 cacheWillUpdate,可以设置哪些 http status 或者 headers 的 response 要缓存,做到更精细的缓存操作。

如何配置我的缓存

离线指南已经提供了一些缓存方式,在 workbox 中,可以大致认为,有一些资源会直接影响整个应用的框架能否显示的(开发应用的 JS,CSS 和部分图片)可以做 precache,这些资源一般不存在“异步”的加载,它们如果不显示整个页面无法正常加载。

那他们的更新策略也很简单,一般这些资源的更新需要发版,而在这里用更新sw文件更新。

对于大部分无状态(注意无状态)数据请求,推荐StaleWhileRevalidate方式或者缓存回退,在某些后端数据变化比较快的情况下,添加失效时间也是可以的,对于其它(业务图片)需求,cache-first比较适用。

最后需要讨论的是页面和有状态的请求,页面是一个比较复杂的情况,页面如果是纯静态的,那么可以放入precache。但要注意,如果我们的页面不是打包工具生成的,页面文件很可能不在dist目录下,那么怎么追踪变化呢,这里推荐一种方式,我们的页面往往有一个模版,和一个json串配置hash变量,那么你可以添加这种模式:

templatedUrls: {path: ['.../xxx.html','.../xxx.json']
}

如果没有json,就需要关联所有可能影响生成页面的数据了,那么这些文件的变化都会改变最后生成的sw文件。

如果你在页面上有一些动态信息(比如用户信息等等),那就比较麻烦了,推荐使用 network-first 配合一个合适的失败时间,毕竟大家都不希望用户登录了另一个账号,显示的还是上一个账号,这同样适用于那些使用cookie(有状态)的请求,这些请求也推荐你添加失效策略,和失败状态。

永远记住你的目标,让用户能够更快的看到页面,但不要给用户一个错误的页面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/22789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

半导体制造中的压缩气体及其高压扩散器如何选择 北京中邦兴业

了解高压扩散器 高压扩散器(HPD)对于保持压缩气体样品中颗粒计数的精度至关重要。它们充当颗粒计数器和压缩气体管线之间的纽带,在气体进入颗粒计数器的样品入口时使其扩散。这确保了压力得到控制,以防止对颗粒计数器样品室的敏感…

uniapp学习(001 前期介绍)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战,开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第1p-第p10的内容 简介 目录结构 效果 打包成小程序 配置开发者工具 打开安全按钮 使用uniapp的内置组件…

3DMAX一键虚线图形插件DashedShape使用方法

3DMAX一键虚线图形插件使用方法 3dMax一键虚线图形插件,允许从场景中拾取的样条线创建虚线形状。该工具使你能够创建完全自定义的填充图案,为线段设置不同的材质ID,并在视口中进行方便的预览。 【版本要求】 3dMax 2012 – 2025(…

数据结构与算法笔记:基础篇 - 数组:为什么数组都是从0开始编号

概述 提到数组,大家应该都不陌生。每一种编程语言基本都会有数组这种数据类型。不过,它不仅仅是一种编程语言中的数据类型,还是一种基础的数据结构。尽管数组看起来非常简单,但是我估计很多人并没有理解这个数据结构的精髓。 在…

AB测试实战

AB测试实战 1、AB测试介绍🐾 很多网站/APP的首页都会挂一张头图(Banner),用来展示重要信息,头图是否吸引人会对公司的营收带来重大影响,一家寿险公司Humana设计了如下三张头图,现在需要决定使用哪一张放到首页&#x…

FastDFS分布式文件系统

一、概述 FastDFS是一款由国人余庆开发的轻量级开源分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,主要解决大容量文件存储和高并发访问问题&#xff0c…

jenkins应用2-freestyle-job

1.jenkins应用 1.jenkins构建的流程 1.使用git参数化构建,用标签区分版本 2.git 拉取gitlab远程仓库代码 3.maven打包项目 4.sonarqube经行代码质量检测 5.自定义制作镜像发送到远程仓库harbor 6.在远程服务器上拉取代码启动容器 这个是构建的整个过程和步骤…

保姆级教程:Redis 主从复制原理及集群搭建

😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD 如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。 😊 座右铭:不…

线程池的工作原理

文章目录 一、应用场景二、工作原理三、主要函数 一、应用场景 传统并发变成的缺陷: 1.创建和销毁线程上花费的时间和消耗的系统资源,甚至可能要比花在处理实际的用户请求的时间和资源要多得多 2. 活动的线程需要消耗系统资源,如果启动太多&…

26、matlab多项式曲线拟合:polyfit ()函数

1、polyfit 多项式曲线拟合 语法 语法:p polyfit(x,y,n) 返回次数为 n 的多项式 p(x) 的系数,该阶数是 y 中数据的最佳拟合(基于最小二乘指标)。 语法:[p,S] polyfit(x,y,n) 还返回一个结构体 S 语法:[…

优化 mac 储存空间的方法 只需一招为你的苹果电脑提速

在职场中,许多人都对苹果电脑情有独钟。苹果电脑以其简洁美观的设计、流畅稳定的性能以及出色的用户体验,成为了众多职场人士的得力助手。无论是处理文档、制作演示文稿,还是进行创意设计等工作,苹果电脑都能展现出其独特的优势&a…

微信小程序公众号二合一分销商城源码系统 基于PHP+MySQL组合开发的 可多商户商家入驻 带完整的安装代码包以及搭建教程

系统概述 微信小程序公众号二合一分销商城源码系统,是基于PHPMySQL组合开发的一款高效、稳定的电子商务平台解决方案。该系统创新性地将微信公众号与小程序的功能进行了深度整合,为商家提供了一个功能齐全、易于管理的分销商城系统。通过此系统&#xf…

Vue3+vant 带你实现常见的历史记录的业务功能

前言 大部分小伙伴不管是开发PC端还是H5移动端,都会遇到历史搜索的功能。对用户的历史记录进行增删查可以是接口,也可以是前端用缓存实现,一般用浏览器缓存实现的比较多,这篇文章就来教你如何用LocalStorage对历史记录数据的存储、…

视创云展元宇宙虚拟展厅,带来沉浸式的逛展体验!

近年来,随着科技的飞速发展和市场需求的不断演变,众多企业纷纷将目光转向线上虚拟展厅的建设。视创云展元宇宙虚拟展厅凭借其创新性和实用性,为众多企业带来了前所未有的宣传体验,成为了商企展示自我、推广产品的全新舞台。 与传统…

Java 生成SSL证书

第一步: cmd打开指令窗口 第二步: 运行指令: keytool -keystore hk.jks -storepass 123456 -deststoretype jks -genkeypair -keyalg RSA -validity 365 -alias contrastserver -dname "CN111.230.63.59, OUHK, OHK, LZH, STGD, CCN&…

XSKY对象存储深度结合Alluxio分布式缓存系统,GPU利用率提高至90%以上

近日,Alluxio分布式缓存系统完成了与XSKY星辰天合的 XEOS V6.4 对象存储的兼容性测试,旨在解决数据管理和加速方面的挑战。双方进行了深度的产品对接和联合开发,将 Alluxio 分布式缓存系统与 XEOS 对象存储的众多应用特性进行结合&#xff0c…

38. 【Java教程】日期和时间处理

本小节我们将学习 Java 中的日期和时间,日期和时间在我们的实际开发中非常常用,例如用户的注册、数据的增删改、对敏感信息的操作等等都需要记录下日期和时间。通过本小节的学习,你将了解到什么是日期、什么是时间、什么是时区,Ja…

3072. 将元素分配到两个数组中 II

题目 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount ,使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。 你需要使用 n 次操作,将 nums 的所有元素分配到两个数组 arr1 和 arr2 中。在第一次操…

WebGL画粗线

目录 前言 基本思路 求左右端点 实现 组织数据 顶点着色器计算端点坐标 效果 前言 WebGL绘制模式有点、线、面三种;通过点的绘制可以实现粒子系统等,通过线可以绘制一些连线关系;面就强大了,通过面,我们可以…

视频监控汇聚平台LntonCVS国标GB28181协议实现语音对讲功能

在当今这个智能技术飞速发展的时代,人工智能已经成为了电子产品领域的一股不可忽视的热门趋势。随着科技的不断进步,越来越多的电子产品开始融入人工智能技术,从而为其开拓了全新的发展路径。在这个大背景下,安防摄像头无插件直播…