此 Codelab 介绍了如何使用 Workbox 实现弹性搜索体验。它使用的演示版应用包含一个搜索框,可调用服务器端点,并将用户重定向到一个基本 HTML 页面。
测量
在添加优化之前,最好先分析应用的当前状态。
- 点击 Remix to Edit 以使项目可修改。
- 如需预览网站,请按查看应用。然后按
全屏
。
在刚刚打开的新标签页中,查看网站离线时的行为:
- 按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
- 点击网络标签页。
- 打开 Chrome 开发者工具并选择 Network 面板。
- 在限制下拉列表中,选择离线。
- 在演示版应用中,输入搜索查询,然后点击 Search 按钮。
标准浏览器错误页面如下所示:
提供后备响应
Service Worker 包含用于将离线网页添加到预缓存列表的代码,以便它始终在出现 Service Worker install
事件时缓存。
通常情况下,您需要指示 Workbox 在构建时将此文件添加到预缓存列表中,方法是将该库与您选择的构建工具(例如 webpack 或 gulp)集成。
为简单起见,我们已为您完成此操作。public/sw.js
中的以下代码即可做到这一点:
const FALLBACK_HTML_URL = '/index_offline.html';
…
workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);
接下来,添加代码以使用离线网页作为后备响应:
- 要查看源代码,请按查看源代码。
- 将以下代码添加到
public/sw.js
的底部:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());
workbox.routing.setCatchHandler(({event}) => {
switch (event.request.destination) {
case 'document':
return caches.match(FALLBACK_HTML_URL);
break;
default:
return Response.error();
}
});
代码会执行以下操作:
- 定义适用于所有请求的默认仅限广告网络策略。
- 通过调用
workbox.routing.setCatchHandler()
管理失败的请求,声明全局错误处理程序。当请求针对的是文档时,系统会返回后备离线 HTML 网页。
如需测试此功能,请执行以下操作:
- 返回运行应用的另一个标签页。
- 将 Throttling 下拉列表重新设置为 Online。
- 按 Chrome 的返回按钮即可返回到搜索页。
- 确保开发者工具中的 Disable cache 复选框处于停用状态。
- 长按 Chrome 的重新加载按钮,然后选择 清空缓存并硬重新加载 以确保您的 Service Worker 得到更新。
- 将限制下拉列表重新设为离线。
- 输入搜索查询,然后再次点击搜索按钮。
系统显示后备 HTML 页面:
请求通知权限
为简单起见,位于 views/index_offline.html
的离线页面已包含用于在底部的脚本块中请求通知权限的代码:
function requestNotificationPermission(event) {
event.preventDefault();
Notification.requestPermission().then(function (result) {
showOfflineText(result);
});
}
代码会执行以下操作:
- 当用户点击订阅通知时,系统会调用
requestNotificationPermission()
函数,该函数会调用Notification.requestPermission()
,以显示默认的浏览器权限提示。promise 使用用户选择的权限进行解析,可以是granted
、denied
或default
。 - 将解析的权限传递给
showOfflineText()
,以便向用户显示适当的文本。
保留离线查询,并在恢复在线状态后重试
接下来,实现 Workbox Background Sync 以保留离线查询,以便在浏览器检测到已返回连接时重试这些查询。
- 打开
public/sw.js
进行修改。 - 在文件末尾添加以下代码:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
maxRetentionTime: 60,
onSync: async ({queue}) => {
let entry;
while ((entry = await queue.shiftRequest())) {
try {
const response = await fetch(entry.request);
const cache = await caches.open('offline-search-responses');
const offlineUrl = `${entry.request.url}¬ification=true`;
cache.put(offlineUrl, response);
showNotification(offlineUrl);
} catch (error) {
await this.unshiftRequest(entry);
throw error;
}
}
},
});
代码会执行以下操作:
workbox.backgroundSync.Plugin
包含将失败请求添加到队列以便稍后重试的逻辑。这些请求将保留在 IndexedDB 中。maxRetentionTime
表示可以重试请求的时长。在本例中,我们选择了 60 分钟(60 分钟之后将舍弃)。onSync
是此代码中最重要的部分。此回调将在连接恢复时调用,以便检索已排队的请求,然后再从网络中提取。- 将网络响应添加到
offline-search-responses
缓存中并附加¬ification=true
查询参数,以便在用户点击通知时获取此缓存条目。
如需将后台同步与您的服务集成,请为发送到搜索网址 (/search_action
) 的请求定义 NetworkOnly 策略,并传递之前定义的 bgSyncPlugin
。将以下代码添加到 public/sw.js
的底部:
const matchSearchUrl = ({url}) => {
const notificationParam = url.searchParams.get('notification');
return url.pathname === '/search_action' && !(notificationParam === 'true');
};
workbox.routing.registerRoute(
matchSearchUrl,
new workbox.strategies.NetworkOnly({
plugins: [bgSyncPlugin],
}),
);
这会告知 Workbox 始终转到网络,并在请求失败时使用后台同步逻辑。
接下来,将以下代码添加到 public/sw.js
的底部,以便为来自通知的请求定义缓存策略。使用 CacheFirst 策略,以便从缓存中提供它们。
const matchNotificationUrl = ({url}) => {
const notificationParam = url.searchParams.get('notification');
return (url.pathname === '/search_action' && (notificationParam === 'true'));
};
workbox.routing.registerRoute(matchNotificationUrl,
new workbox.strategies.CacheFirst({
cacheName: 'offline-search-responses',
})
);
最后,添加代码以显示通知:
function showNotification(notificationUrl) {
if (Notification.permission) {
self.registration.showNotification('Your search is ready!', {
body: 'Click to see you search result',
icon: '/img/workbox.jpg',
data: {
url: notificationUrl
}
});
}
}
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(
clients.openWindow(event.notification.data.url)
);
});
测试功能
- 返回运行应用的另一个标签页。
- 将 Throttling 下拉列表重新设置为 Online。
- 按 Chrome 的返回按钮即可返回到搜索页。
- 长按 Chrome 的重新加载按钮,然后选择 清空缓存并硬重新加载 以确保您的 Service Worker 得到更新。
- 将限制下拉列表重新设为离线。
- 输入搜索查询,然后再次点击搜索按钮。
- 点击订阅通知。
- 当 Chrome 询问您是否要授予该应用发送通知的权限时, 点击允许。
- 输入其他搜索查询,然后再次点击搜索按钮。
- 将 Throttling 下拉列表重新设为 Online(在线)。
连接恢复后,系统会显示一条通知:
总结
Workbox 提供了许多内置功能,可让您的 PWA 更具弹性和吸引力。 在此 Codelab 中,您已探索了如何通过 Workbox 抽象实现 Background Sync API,以确保离线用户查询不会丢失,并且可以在连接恢复后重试。 此演示是一款简单的搜索应用,但您可以对更复杂的场景和用例(包括聊天应用、在社交网络上发布消息等)使用类似的实现。