推荐答案
Service Workers 是一种运行在浏览器后台的脚本,独立于网页,可以拦截并处理网络请求、管理缓存以及推送消息。其主要作用包括:
- 离线体验: 通过缓存静态资源和 API 响应,即使在网络连接断开的情况下也能提供网页访问。
- 后台同步: 在后台执行数据同步,即使网页关闭也能保持数据更新。
- 推送通知: 可以接收服务器推送的通知并展示给用户。
- 网络代理: 拦截网络请求并进行自定义处理,例如实现请求重定向、请求修改等。
实现离线缓存的步骤:
注册 Service Worker: 在网页的 JavaScript 代码中注册 Service Worker。
// www.javascriptcn.com code example if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('Service Worker registered with scope:', registration.scope); }) .catch(error => { console.error('Service Worker registration failed:', error); }); }安装 Service Worker: 在
service-worker.js文件中,监听install事件,预缓存静态资源。// www.javascriptcn.com code example const CACHE_NAME = 'my-site-cache-v1'; const URLS_TO_CACHE = [ '/', '/index.html', '/styles.css', '/script.js', '/logo.png' ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('Opened cache'); return cache.addAll(URLS_TO_CACHE); }) ); });拦截请求: 监听
fetch事件,优先从缓存中获取资源,如果缓存中没有,则发起网络请求并缓存响应。// www.javascriptcn.com code example self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(cachedResponse => { if (cachedResponse) { return cachedResponse; // 从缓存中返回 } return fetch(event.request).then(networkResponse =>{ if(!networkResponse || networkResponse.status !== 200 || networkResponse.type !== 'basic'){ return networkResponse } const responseToCache = networkResponse.clone(); caches.open(CACHE_NAME).then(cache=>{ cache.put(event.request,responseToCache) }) return networkResponse });//发起网络请求 }) ); });更新缓存: 监听
activate事件,清理旧版本的缓存。// www.javascriptcn.com code example self.addEventListener('activate', event => { const cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(cacheNames =>{ return Promise.all( cacheNames.map(cacheName =>{ if(cacheWhitelist.indexOf(cacheName) === -1){ return caches.delete(cacheName) } }) ) }) ); });
本题详细解读
什么是 Service Worker
Service Workers 是一个运行在浏览器后台的脚本,它独立于网页,可以拦截并处理网络请求、管理缓存以及推送消息。它本质上是一个 Web Worker,因此没有 DOM 访问权限,必须通过 postMessage 等方法进行通信。Service Workers 运行于 HTTPS 环境,这是为了保证安全。
Service Workers 的生命周期
Service Workers 的生命周期主要分为以下几个阶段:
- 注册 (Registration): 浏览器通过
navigator.serviceWorker.register()方法注册 Service Worker。 - 安装 (Installation): 注册成功后,浏览器会尝试安装 Service Worker。在这个阶段,通常会预缓存静态资源。
- 激活 (Activation): 安装成功后,Service Worker 进入激活状态,此时可以处理
fetch事件。激活阶段通常会清理旧版本缓存。 - 闲置 (Idle): 当没有事件需要处理时,Service Worker 会进入闲置状态。
- 终止 (Termination): 当浏览器不再需要 Service Worker 时,会终止其运行。
离线缓存的实现原理
Service Workers 通过以下几个核心步骤实现离线缓存:
- 安装阶段预缓存: 在
install事件中,通过caches.open()打开一个缓存,并使用cache.addAll()批量缓存需要离线访问的静态资源。 - 拦截请求: 在
fetch事件中,通过caches.match()查找缓存中是否存在请求的资源。 - 优先使用缓存: 如果在缓存中找到资源,直接返回缓存的响应,避免网络请求。
- 网络请求与缓存更新: 如果缓存中没有对应的资源,则发起网络请求。在网络响应成功后,将响应克隆一份,并存入缓存。
- 激活阶段清理旧缓存: 在
activate事件中,清理旧版本的缓存,确保缓存的版本更新。
Service Worker 缓存策略
Service Worker 支持多种缓存策略,常见的包括:
- Cache First: 优先从缓存中获取,如果缓存不存在,则发起网络请求。
- Network First: 优先发起网络请求,如果网络请求失败,则返回缓存的响应。
- Cache Only: 只从缓存中获取,如果缓存不存在,则返回错误。
- Network Only: 只发起网络请求,不使用缓存。
- Stale-while-revalidate: 先返回缓存的响应,同时发起网络请求更新缓存,下次请求返回新的响应。
代码详解
在上面的“推荐答案”中,代码实现了以下功能:
- 注册 Service Worker: 检查浏览器是否支持 Service Worker,如果支持,则注册
/service-worker.js文件。 - 缓存静态资源 (install 事件): 在 Service Worker 安装时,创建名为
my-site-cache-v1的缓存,并缓存URLS_TO_CACHE中列出的静态资源,如主页、样式表、脚本和图像。 - 拦截请求 (fetch 事件): 当网页请求资源时,Service Worker 拦截该请求,先查找缓存中是否有匹配的资源。如果有则返回缓存,否则发起网络请求,并将成功的响应缓存起来。
- 缓存更新 (activate 事件): 在 Service Worker 激活时,检查当前缓存名称是否在白名单中,删除不在白名单中的缓存。
注意事项
- Service Worker 运行于 HTTPS 环境。
- Service Worker 的
install和activate事件只会执行一次,除非 Service Worker 文件发生更新。 - Service Worker 必须处理
fetch事件,否则默认会发起网络请求。 - Service Worker 的生命周期管理需要注意,防止出现缓存不一致的情况。
- Service Worker 的作用域是它所在目录及其子目录。
- 需要考虑到缓存过期策略,可以使用时间戳或其他方式来管理缓存的过期。