在 cache-first Service Worker 上加载后刷新页面
Refresh page after load on cache-first Service Worker
我目前正在考虑将服务工作者添加到我正在构建的 Web 应用程序中。
这个应用本质上是一个 collection 管理器。您可以对各种类型的项目进行 CRUD,它们通常紧密链接在一起(例如 A hasMany B hasMany C)。
sw-toolbox 提供了一个 toolbox.fastest
处理程序,它先访问缓存,然后再访问网络(在 99% 的情况下,缓存会更快),在后台更新缓存。我想知道的是如何通知您该页面有新版本可用。我的目的是显示缓存的版本,然后,如果网络获取有更新的版本,建议用户刷新页面以查看最新的编辑。我刚才在 YouTube video 中看到了一些东西,但是演示者没有给出如何处理这个的线索。
这可能吗?是否有一些事件处理程序或承诺我可以绑定到请求,以便我知道何时检索到较新的版本?然后我会 post 向页面发送消息以显示通知。
如果没有,我知道我可以使用 toolbox.networkFirst
以及合理的超时时间来使页面即使在 Lie-Fi 上也可用,但效果不佳。
我偶然发现了 Mozilla Service Worker Cookbooj,它或多或少包含了我想要的内容:https://serviceworke.rs/strategy-cache-update-and-refresh.html
以下是相关部分(不是我的代码:为方便起见复制在这里)。
工人的获取方法
// On fetch, use cache but update the entry with the latest contents from the server.
self.addEventListener('fetch', function(evt) {
console.log('The service worker is serving the asset.');
// You can use respondWith() to answer ASAP…
evt.respondWith(fromCache(evt.request));
// ...and waitUntil() to prevent the worker to be killed until the cache is updated.
evt.waitUntil(
update(evt.request)
// Finally, send a message to the client to inform it about the resource is up to date.
.then(refresh)
);
});
// Open the cache where the assets were stored and search for the requested resource. Notice that in case of no matching, the promise still resolves but it does with undefined as value.
function fromCache(request) {
return caches.open(CACHE).then(function (cache) {
return cache.match(request);
});
}
// Update consists in opening the cache, performing a network request and storing the new response data.
function update(request) {
return caches.open(CACHE).then(function (cache) {
return fetch(request).then(function (response) {
return cache.put(request, response.clone()).then(function () {
return response;
});
});
});
}
// Sends a message to the clients.
function refresh(response) {
return self.clients.matchAll().then(function (clients) {
clients.forEach(function (client) {
// Encode which resource has been updated. By including the ETag the client can check if the content has changed.
var message = {
type: 'refresh',
url: response.url,
// Notice not all servers return the ETag header. If this is not provided you should use other cache headers or rely on your own means to check if the content has changed.
eTag: response.headers.get('ETag')
};
// Tell the client about the update.
client.postMessage(JSON.stringify(message));
});
});
}
"resource was updated" 消息的处理
navigator.serviceWorker.onmessage = function (evt) {
var message = JSON.parse(evt.data);
var isRefresh = message.type === 'refresh';
var isAsset = message.url.includes('asset');
var lastETag = localStorage.currentETag;
// ETag header usually contains the hash of the resource so it is a very effective way of check for fresh content.
var isNew = lastETag !== message.eTag;
if (isRefresh && isAsset && isNew) {
// Escape the first time (when there is no ETag yet)
if (lastETag) {
// Inform the user about the update.
notice.hidden = false;
}
//For teaching purposes, although this information is in the offline cache and it could be retrieved from the service worker, keeping track of the header in the localStorage keeps the implementation simple.
localStorage.currentETag = message.eTag;
}
};
我目前正在考虑将服务工作者添加到我正在构建的 Web 应用程序中。
这个应用本质上是一个 collection 管理器。您可以对各种类型的项目进行 CRUD,它们通常紧密链接在一起(例如 A hasMany B hasMany C)。
sw-toolbox 提供了一个 toolbox.fastest
处理程序,它先访问缓存,然后再访问网络(在 99% 的情况下,缓存会更快),在后台更新缓存。我想知道的是如何通知您该页面有新版本可用。我的目的是显示缓存的版本,然后,如果网络获取有更新的版本,建议用户刷新页面以查看最新的编辑。我刚才在 YouTube video 中看到了一些东西,但是演示者没有给出如何处理这个的线索。
这可能吗?是否有一些事件处理程序或承诺我可以绑定到请求,以便我知道何时检索到较新的版本?然后我会 post 向页面发送消息以显示通知。
如果没有,我知道我可以使用 toolbox.networkFirst
以及合理的超时时间来使页面即使在 Lie-Fi 上也可用,但效果不佳。
我偶然发现了 Mozilla Service Worker Cookbooj,它或多或少包含了我想要的内容:https://serviceworke.rs/strategy-cache-update-and-refresh.html
以下是相关部分(不是我的代码:为方便起见复制在这里)。
工人的获取方法
// On fetch, use cache but update the entry with the latest contents from the server.
self.addEventListener('fetch', function(evt) {
console.log('The service worker is serving the asset.');
// You can use respondWith() to answer ASAP…
evt.respondWith(fromCache(evt.request));
// ...and waitUntil() to prevent the worker to be killed until the cache is updated.
evt.waitUntil(
update(evt.request)
// Finally, send a message to the client to inform it about the resource is up to date.
.then(refresh)
);
});
// Open the cache where the assets were stored and search for the requested resource. Notice that in case of no matching, the promise still resolves but it does with undefined as value.
function fromCache(request) {
return caches.open(CACHE).then(function (cache) {
return cache.match(request);
});
}
// Update consists in opening the cache, performing a network request and storing the new response data.
function update(request) {
return caches.open(CACHE).then(function (cache) {
return fetch(request).then(function (response) {
return cache.put(request, response.clone()).then(function () {
return response;
});
});
});
}
// Sends a message to the clients.
function refresh(response) {
return self.clients.matchAll().then(function (clients) {
clients.forEach(function (client) {
// Encode which resource has been updated. By including the ETag the client can check if the content has changed.
var message = {
type: 'refresh',
url: response.url,
// Notice not all servers return the ETag header. If this is not provided you should use other cache headers or rely on your own means to check if the content has changed.
eTag: response.headers.get('ETag')
};
// Tell the client about the update.
client.postMessage(JSON.stringify(message));
});
});
}
"resource was updated" 消息的处理
navigator.serviceWorker.onmessage = function (evt) {
var message = JSON.parse(evt.data);
var isRefresh = message.type === 'refresh';
var isAsset = message.url.includes('asset');
var lastETag = localStorage.currentETag;
// ETag header usually contains the hash of the resource so it is a very effective way of check for fresh content.
var isNew = lastETag !== message.eTag;
if (isRefresh && isAsset && isNew) {
// Escape the first time (when there is no ETag yet)
if (lastETag) {
// Inform the user about the update.
notice.hidden = false;
}
//For teaching purposes, although this information is in the offline cache and it could be retrieved from the service worker, keeping track of the header in the localStorage keeps the implementation simple.
localStorage.currentETag = message.eTag;
}
};