Informace o této programovací laboratoři
1. 欢迎
在本实验中,您将使用一个现有的 Web 应用,并使其能够离线运行。这是渐进式 Web 应用研讨会的一系列配套 Codelab 中的第一个。本系列还有 7 个 Codelab。
学习内容
- 手动编写 Service Worker
- 向现有 Web 应用添加 Service Worker
- 使用 Service Worker 和 Cache Storage API 使资源可离线使用
注意事项
- HTML 和 JavaScript 基础知识
所需条件
- 支持 Service Worker 的浏览器
2. 进行设置
首先,克隆或下载完成此 Codelab 所需的起始代码:
如果您克隆了代码库,请确保您位于 starter
分支中。该 ZIP 文件还包含相应分支的代码。
此代码库需要 Node.js 14 或更高版本。获得代码后,在代码的文件夹中通过命令行运行 npm ci
,以安装所需的所有依赖项。然后,运行 npm start
以启动 Codelab 的开发服务器。
源代码的 README.md
文件提供了对所有分发文件的说明。此外,以下是您将在整个 Codelab 中使用的关键现有文件:
密钥文件
js/main.js
- 主要应用 JavaScript 文件service-worker.js
- 应用的服务工作线程文件
3. 离线测试
在进行任何更改之前,我们先进行测试,以表明该 Web 应用目前无法离线运行。为此,您可以让计算机离线并重新加载 Web 应用,也可以执行以下操作(如果您使用的是 Chrome):
- 打开 Chrome 开发者工具
- 切换到“应用”标签页
- 切换到“Service Worker”部分
- 勾选“离线”复选框
- 刷新网页,但不关闭 Chrome 开发者工具
在测试网站并成功使其无法离线加载后,接下来就可以添加一些在线功能了!取消选中“离线”复选框,然后继续执行下一步。
4. 下播后延续互动
现在,可以添加基本的服务工作线程了!此过程将分两步进行:注册 service worker 和缓存资源。
注册 Service Worker
我们已经有了一个空的 Service Worker 文件,因此为了确保更改生效,我们将在应用中注册该文件。为此,请将以下代码添加到 js/main.js
的顶部:
// Register the service worker
if ('serviceWorker' in navigator) {
// Wait for the 'load' event to not block other work
window.addEventListener('load', async () => {
// Try to register the service worker.
try {
// Capture the registration for later use, if needed
let reg;
// Use ES Module version of our Service Worker in development
if (import.meta.env?.DEV) {
reg = await navigator.serviceWorker.register('/service-worker.js', {
type: 'module',
});
} else {
// In production, use the normal service worker registration
reg = await navigator.serviceWorker.register('/service-worker.js');
}
console.log('Service worker registered! 😎', reg);
} catch (err) {
console.log('😥 Service worker registration failed: ', err);
}
});
}
说明
此代码会在页面加载后注册空的 service-worker.js
Service Worker 文件,前提是网站支持 Service Worker。
预缓存资源
为了让 Web 应用在离线状态下正常运行,浏览器需要能够响应网络请求并选择将这些请求路由到何处。为此,请将以下内容添加到 service-worker.js
// Choose a cache name
const cacheName = 'cache-v1';
// List the files to precache
const precacheResources = ['/', '/index.html', '/css/style.css', '/js/main.js', '/js/app/editor.js', '/js/lib/actions.js'];
// When the service worker is installing, open the cache and add the precache resources to it
self.addEventListener('install', (event) => {
console.log('Service worker install event!');
event.waitUntil(caches.open(cacheName).then((cache) => cache.addAll(precacheResources)));
});
self.addEventListener('activate', (event) => {
console.log('Service worker activate event!');
});
// When there's an incoming fetch request, try and respond with a precached resource, otherwise fall back to the network
self.addEventListener('fetch', (event) => {
console.log('Fetch intercepted for:', event.request.url);
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request);
}),
);
});
现在,返回浏览器,关闭预览标签页,然后重新打开。您应该会看到与 Service Worker 中的不同事件对应的 console.log
!
接下来,再次离线并刷新网站。您应该会看到,即使处于离线状态,该网页也会加载!
说明
在 service worker 的安装事件期间,使用 Cache Storage API 打开一个命名缓存。然后,使用 cache.addAll
方法将 precacheResources
中指定的文件和路由加载到缓存中。之所以称为“预缓存”,是因为它会在安装时预先缓存一组文件,而不是在需要或请求这些文件时再进行缓存。
一旦 service worker 控制了网站,所请求的资源就会像通过代理一样通过 service worker。每个请求都会触发一个提取事件,该事件会在相应服务工作线程中搜索缓存以查找匹配项,如果找到匹配项,则会使用缓存的资源进行响应。如果没有匹配项,则正常请求资源。
缓存资源可避免网络请求,从而使应用能够离线运行。现在,应用在离线时也能成功做出响应,并返回 200 状态代码!