serviceworke.rs 是一个包含常见和 不常见 Service Worker 用例的汇编,包括推送示例、使用模式、性能技巧和缓存策略。
Service Worker 食谱中的菜谱以游乐场或实验室的形式呈现,包含功能完备的客户端-服务器设置,您可以在其中使用浏览器内开发者工具学习和实验结果。
然而,食谱远非全面,我们意识到它缺少一些基本材料和用户反馈机制。今天,我很自豪地宣布 Service Worker 食谱的一些变化,首先是关于 **缓存策略** 的新部分。
缓存策略
缓存策略包含演示几种从服务工作者提供内容的方法的菜谱。这些菜谱遵循相同的布局,其中两个 iframe 并排显示。两者都显示一个指向同一在线图片的图像元素。
第一个 iframe 不受服务工作者拦截,因此图片始终显示来自服务器的最新内容。相反,第二个 iframe 受服务工作者控制,内容根据实施的缓存策略提供。
图片内容每 10 秒在服务器上更改,您有一个按钮可以同时刷新两个 iframe 并比较图片的变化。
一些缓存策略来自 Jake Archibald 的《离线食谱》 中的一篇鼓舞人心的文章,其他则是我们自己开发的。
仅缓存
最基本的示例:使用 *仅缓存*,请求永远不会到达网络。相反,它们将由服务工作者从本地缓存中提供。
self.addEventListener('fetch', function(evt) {
evt.respondWith(fromCache(evt.request));
});
function fromCache(request) {
return caches.open(CACHE).then(function (cache) {
return cache.match(request).then(function (matching) {
return matching || Promise.reject('no-match');
});
});
}
在此实施中,仅缓存的资产在安装服务工作者时存储,并将一直保留在那里,直到安装了新版本的 worker。
self.addEventListener('install', function(evt) {
evt.waitUntil(precache());
});
function precache() {
return caches.open(CACHE).then(function (cache) {
return cache.addAll([
'./controlled.html',
'./asset'
]);
});
}
您可以将 **仅缓存策略** 用于您网站的 UI 相关资产,例如图像、HTML、精灵图或 CSS 文件。
缓存和更新
仅缓存策略的这种细微变化也从本地缓存中提供资产,但它也发送网络请求以获取资产的更新版本。新内容然后替换本地缓存中的旧资产。
self.addEventListener('fetch', function(evt) {
evt.respondWith(fromCache(evt.request));
evt.waitUntil(update(evt.request));
});
function update(request) {
return caches.open(CACHE).then(function (cache) {
return fetch(request).then(function (response) {
return cache.put(request, response);
});
});
}
使用这种 **缓存和更新策略**,您的资产将不再与在线资产同步,但它们将在第二次请求(大致相当于第二次访问)时同步。
在传递独立的、非关键内容(例如头像或图标)时,使用此策略完全没问题。避免依赖于此策略传递依赖资产(例如完整的 UI 主题),因为没有保证资产会按需同时更新。
缓存、更新和刷新
对先前策略的又一次调整,现在添加了 **刷新成分**。
使用 **缓存、更新和刷新**,客户端将在新内容可用时收到服务工作者的通知。这样,您的网站就可以显示内容,而无需等待网络响应,同时为 UI 提供了一种以受控方式显示最新内容的方法。
self.addEventListener('fetch', function(evt) {
evt.respondWith(fromCache(evt.request));
evt.waitUntil(
update(evt.request)
.then(refresh)
);
});
function refresh(response) {
return self.clients.matchAll().then(function (clients) {
clients.forEach(function (client) {
var message = {
type: 'refresh',
url: response.url,
eTag: response.headers.get('ETag')
};
client.postMessage(JSON.stringify(message));
});
});
}
这在获取任何类型的内容时特别有用。这与之前的策略不同,因为它不需要用户刷新或第二次访问网站。因为客户端知道新内容,所以 UI 可以在智能、非侵入性的方式中更新。
嵌入式回退
在某些情况下,您始终希望始终显示某些内容来替换由于任何原因(网络错误、404、无连接)而缺失的内容。通过将 **该内容嵌入到服务工作者** 中,可以确保始终可用离线内容。
self.addEventListener('fetch', function(evt) {
evt.respondWith(networkOrCache(evt.request).catch(function () {
return useFallback();
}));
});
// Dunno why this is shown as the actual SVG in WordPress but it looks awesome!
// You can see the source code in the recipe.
var FALLBACK =
'' +
' ' +
' ' +
' ' +
' ' +
'';
function useFallback() {
return Promise.resolve(new Response(FALLBACK, { headers: {
'Content-Type': 'image/svg+xml'
}}));
}
在此菜谱中,作为缺失内容替换的 SVG 包含在 worker 中。一旦安装,回退将在不执行新的网络请求的情况下可用。
网络或缓存
Service Workers 将自己置于客户端和互联网之间。在某种程度上,它们允许开发者模拟他们理想的网络行为。此策略通过对网络响应施加时间限制来利用/增强这种想法。
self.addEventListener('fetch', function(evt) {
evt.respondWith(fromNetwork(evt.request, 400).catch(function () {
return fromCache(evt.request);
}));
});
function fromNetwork(request, timeout) {
return new Promise(function (fulfill, reject) {
var timeoutId = setTimeout(reject, timeout);
fetch(request).then(function (response) {
clearTimeout(timeoutId);
fulfill(response);
}, reject);
});
}
使用此菜谱,请求由服务工作者拦截并传递到网络。如果响应花费的时间过长,则会中断该过程,并从本地缓存中提供内容。
**有时间限制的网络或缓存** 实际上可以与任何其他技术结合使用。该策略只是让网络有机会快速使用最新内容进行响应。
用户反馈
我们想知道这些菜谱是否有用,以及您是否觉得它们清晰或令人困惑。它们是否提供了独特的价值,或者它们是多余的?我们在菜谱中添加了 Disqus 评论,以便您分享您的反馈。使用 Facebook、Twitter、Google 或 Disqus 登录,并告诉我们此菜谱是如何为您服务的,或者参与有关推荐用例的讨论。
以及更多即将推出的内容
我们不会止步于此。更多菜谱即将推出,新增强功能也即将推出:改进的请求菜谱方法、更简单的贡献流程、视觉更新和更新后的菜谱布局是我们正在考虑的事情。如果您喜欢 **serviceworke.rs**,请与您的朋友和同事分享。随意在您的演讲或演示文稿中使用这些菜谱,最重要的是,通过在网站上发表评论、提交 GitHub 问题或 直接发推给我 来帮助我们 😉
您的意见真的非常感谢!
关于 Salva
Mozilla 的前端开发者。开放网络和 WebVR 倡导者,我喜欢编程语言、电影、音乐、电子游戏和啤酒。
4 条评论