众所周知,使用 Service Worker 技术可以实现 PWA,提升 Web 应用的性能和用户体验。其中一个重要功能就是缓存,使得应用可以离线使用。但是在更新版本的应用中,也会遇到图片缓存不刷新的问题,这让很多开发者头疼。本文旨在介绍如何快速解决图片缓存不刷新的问题。
缓存图像的问题
首先,我们需要了解缓存带来的问题。在使用 Service Worker 缓存图像时,因为图像的大小、数量都很大,所以需要在改动时及时更新缓存,否则会遇到图片不更新或者不显示的情况。
在默认情况下,Service Worker 会缓存所有来自同一 URL 的资源文件,一个 URL 对应了一个状态。如果某个文件的状态发生了变化,那么它的 URL 也会发生变化。于是就会出现这样的情况:即使代码已经更新,页面还是自缓存以来的版本。
解决方案
针对缓存图像的问题,一种最简单明了的解决方案是给每个图片URL添加版本号,这样当图片内容发生变化时,URL 中的版本号也会随之改变,从而服务端能为客户端返回新版本的图片,这确保了缓存的图像和实时的图像相符。下面我们就来具体介绍如何实现。
1. 缓存清理策略
我们可以添加一个占位符,通过改变 URL 参数的方式实现版本控制,例如:
const cacheVersion = 'v1'; const imageUrl = `/image.png?v=${cacheVersion}`;
这里我们将 ?v=
后面的版本号设置为 v1
,作为占位符。每次有代码更新时,我们只需要改动一下 v1
为 v2
,就可以保证图片更新失效,触发更新。
接下来,我们需要实现一个缓存清理策略。具体地,当客户端与服务端连接时,需要检查当前的版本号是否与本地保存的版本一致,如果不一致,则需要执行缓存清理操作。代码实现如下:
// javascriptcn.com 代码示例 self.addEventListener('fetch', event => { if (event.request.url.match(/.*\.png/)) { const cacheBusterMatch = event.request.url.match(/[?|&]v=(.*)$/); const currentCacheVersion = cacheBusterMatch ? cacheBusterMatch[1] : 'v1'; event.respondWith( caches.match(event.request, { ignoreSearch: true }).then(response => { if (response) { const cachedVersion = response.url.match(/[?|&]v=(.*)$/); if (cachedVersion && cachedVersion[1] !== currentCacheVersion) { caches.delete(response.url); location.reload(true); } return response; } return fetch(event.request); }), ); } });
这段代码实现了一个最简单的缓存清理策略。我们在 fetch
事件中监视页面上所有的图像请求,并检查 v=
参数。如果 v=
中的版本号不匹配,我们就删除缓存中的图像,并强制重新加载页面。如果匹配,则返回本地缓存。
2. Service Worker 更新
有了缓存清理策略后,我们还需要在每次 Service Worker 实例化时检查版本号是否一致,如果不一致,需要更新 Service Worker。
// javascriptcn.com 代码示例 const cacheVersion = 'v2'; const cacheName = `my-cache-${cacheVersion}`; self.addEventListener('install', event => { event.waitUntil( caches .open(cacheName) .then(cache => cache.addAll([ '/', '/index.html', '/styles.css', `/image.png?v=${cacheVersion}`, ]), ) .then(() => self.skipWaiting()) ); }); self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(keyList => Promise.all( keyList.map(key => { if (key !== cacheName) { return caches.delete(key); } return null; }), ), ).then(() => { self.clients.claim(); }), ); }); self.addEventListener('fetch', event => { // fetch 拦截器代码 });
这里我们用一个常量 cacheVersion
来控制缓存版本,每次需要更新时,只需更新该常量的值。在 install
事件中,我们添加需要缓存的文件,并给图片添加版本号。同时,在 activiate
事件中,我们需要删除旧版本的缓存。
3. 页面代码
最后,我们应该对页面代码做出相应的调整,以确保每个请求的 URL 都包含 ?v=
参数,代码如下:
<img src="/image.png?v=`${cacheVersion}`" />
总结
至此,我们成功解决了图片缓存不刷新的问题。我们通过为图片URL添加版本号,实现了版本控制,并且通过添加缓存清理策略,使得缓存可以更新。在实际开发中,可以根据实际情况来做出相应的调整。同时,我们还需要注意,由于添加了版本号,相同的图片也会被认为是不同的图片,因此在调用图片时需要格外注意,以免出现不必要的错误。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652c948d7d4982a6ebe3f7da