将响应图像离线回退到最大的缓存图像
Offline fallback for responsive images to largest cached image
我有一个使用图像 srcset 的项目。它们都在自己的子目录中,类似于:
- /images/image1/100.jpg, 200.jpg, 500.jpg, 1000.jpg
- /images/image2/100.jpg, 200.jpg, 500.jpg, 1000.jpg
该站点在列表和详细视图中使用不同大小的图像。例如,从纵向移动到横向将从 100.jpg 变为 200.jpg,详细视图将使用 500 或 1000.jpg,具体取决于视口大小。
在离线情况下,是否有可能让工作箱查找使用以“/images/image1/”开头的 URI 缓存的内容,并找到编号最大的文件和 return?如果离线用户发生变化,我宁愿使用更小(或更大)的图像而不是损坏的图像。从纵向到横向。
好的!这是一个 requires Workbox v6, and makes use of the new handlerDidError
lifecycle event 提供后备的自定义插件:
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
// Replace with your desired cache name.
const imagesCacheName = 'images-cache';
function parseImageNameAndSize(url) {
const pattern = new RegExp('/([^/]+)/(\d+)\.jpg$');
const [_, name, size] = pattern.exec(url) || [];
// This will return [undefined, NaN] when there's no match.
return [name, parseInt(size)];
}
async imageFallback({error, request}) {
let largestSize = -1;
let cacheKeyOfLargestImage;
const [originalName, _] = parseImageNameAndSize(request.url);
// If the URL doesn't match our RegExp, re-throw the underlying error.
if (!originalName) {
throw error;
}
const cache = await caches.open(imagesCacheName);
const cachedRequests = await cache.keys();
// Iterate through all of the cache entries to find matches:
for (const cachedRequest of cachedRequests) {
const [name, size] = parseImageNameAndSize(cachedRequest.url);
if ((name === originalName) && (size > largestSize)) {
largestSize = size;
cacheKeyOfLargestImage = cachedRequest;
}
}
if (cacheKeyOfLargestImage) {
// If we have the cache key for the largest image that meets
// the conditions, return the cached response.
return cache.match(cacheKeyOfLargestImage);
}
// If there is no image the cache that satisfies these conditions,
// re-throw the underlying error.
throw error;
}
// Now, use the callback as a plugin by associating it with
// handerDidError in the strategy of your choice
// (CacheFirst, StaleWhileRevalidate, etc.):
registerRoute(
// Match any request whose path ends in .jpg
({url}) => url.pathname.endsWith('.jpg'),
new CacheFirst({
cacheName: imagesCacheName,
plugins: [
{handlerDidError: imageFallback},
// Add any other plugins you want.
],
})
);
(我还没有测试所有这些代码,但我认为它应该接近工作。如果您 运行 遇到问题请告诉我!)
请注意,只有在给定策略无法满足 URL 的原始请求时,此插件才会“启动”,这很可能是因为您处于离线状态并且没有缓存匹配。如果您想配置 Workbox,使其始终在缓存中可用时使用最高质量的图像,即使您在线或缓存匹配较低的图像时也是如此-质量图像,可以这样做(可能在 cachedResponseWillBeUsed
回调中)。但我认为对于您描述的特定用例,使用新的 handlerDidError
回调是最好的方法。
我有一个使用图像 srcset 的项目。它们都在自己的子目录中,类似于:
- /images/image1/100.jpg, 200.jpg, 500.jpg, 1000.jpg
- /images/image2/100.jpg, 200.jpg, 500.jpg, 1000.jpg
该站点在列表和详细视图中使用不同大小的图像。例如,从纵向移动到横向将从 100.jpg 变为 200.jpg,详细视图将使用 500 或 1000.jpg,具体取决于视口大小。
在离线情况下,是否有可能让工作箱查找使用以“/images/image1/”开头的 URI 缓存的内容,并找到编号最大的文件和 return?如果离线用户发生变化,我宁愿使用更小(或更大)的图像而不是损坏的图像。从纵向到横向。
好的!这是一个 requires Workbox v6, and makes use of the new handlerDidError
lifecycle event 提供后备的自定义插件:
import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
// Replace with your desired cache name.
const imagesCacheName = 'images-cache';
function parseImageNameAndSize(url) {
const pattern = new RegExp('/([^/]+)/(\d+)\.jpg$');
const [_, name, size] = pattern.exec(url) || [];
// This will return [undefined, NaN] when there's no match.
return [name, parseInt(size)];
}
async imageFallback({error, request}) {
let largestSize = -1;
let cacheKeyOfLargestImage;
const [originalName, _] = parseImageNameAndSize(request.url);
// If the URL doesn't match our RegExp, re-throw the underlying error.
if (!originalName) {
throw error;
}
const cache = await caches.open(imagesCacheName);
const cachedRequests = await cache.keys();
// Iterate through all of the cache entries to find matches:
for (const cachedRequest of cachedRequests) {
const [name, size] = parseImageNameAndSize(cachedRequest.url);
if ((name === originalName) && (size > largestSize)) {
largestSize = size;
cacheKeyOfLargestImage = cachedRequest;
}
}
if (cacheKeyOfLargestImage) {
// If we have the cache key for the largest image that meets
// the conditions, return the cached response.
return cache.match(cacheKeyOfLargestImage);
}
// If there is no image the cache that satisfies these conditions,
// re-throw the underlying error.
throw error;
}
// Now, use the callback as a plugin by associating it with
// handerDidError in the strategy of your choice
// (CacheFirst, StaleWhileRevalidate, etc.):
registerRoute(
// Match any request whose path ends in .jpg
({url}) => url.pathname.endsWith('.jpg'),
new CacheFirst({
cacheName: imagesCacheName,
plugins: [
{handlerDidError: imageFallback},
// Add any other plugins you want.
],
})
);
(我还没有测试所有这些代码,但我认为它应该接近工作。如果您 运行 遇到问题请告诉我!)
请注意,只有在给定策略无法满足 URL 的原始请求时,此插件才会“启动”,这很可能是因为您处于离线状态并且没有缓存匹配。如果您想配置 Workbox,使其始终在缓存中可用时使用最高质量的图像,即使您在线或缓存匹配较低的图像时也是如此-质量图像,可以这样做(可能在 cachedResponseWillBeUsed
回调中)。但我认为对于您描述的特定用例,使用新的 handlerDidError
回调是最好的方法。