Service Worker初识 --派大星的开发日记
个人开发记录笔记,仅个人理解,有错误还请指出
概述
Service Worker API是现代Web开发中一个强大的工具,它允许开发者创建高效离线体验和进行资源缓存。Service Worker本质上是Web应用、浏览器和网络之间的代理服务器,它能够拦截网络请求并根据网络状况采取相应的行动,同时还能推送通知和访问后台同步API。
核心特性
- 离线体验:Service Worker使得Web应用即使在没有网络连接的情况下也能运行。
- 资源拦截与修改:可以拦截页面或网站的资源请求,并进行修改。
- 后台操作:Service Worker运行在独立的线程中,不会阻塞主线程。
- 安全性:只能通过HTTPS协议启用,以防止中间人攻击。
- 异步操作:大量使用Promise,适合处理异步事件。
生命周期
Service Worker的生命周期包括下载、安装和激活三个阶段。一旦注册,Service Worker将控制整个域内用户可访问的URL,或者其特定子集。
- 下载:用户首次访问时,Service Worker被下载。
- 安装:如果下载的文件是最新的,将尝试安装。
- 激活:安装成功后,Service Worker被激活。
使用场景
Service Worker不仅可以用于创建离线体验,还有其他多种用途:
- 后台数据同步
- 响应来自其他源的资源请求
- 集中处理高成本数据更新
- 客户端模块编译和依赖管理
- 后台服务钩子
- 自定义模板
- 性能增强,如预加载资源
提供接口
- Cache
- 功能:表示用于
Request
/Response
对象对的存储,作为ServiceWorker
生命周期的一部分被缓存。 - 方法:
cache.match(request)
:查找与给定请求匹配的缓存响应。cache.addAll(requests)
:将多个资源添加到缓存中。
- 功能:表示用于
- CacheStorage
- 功能:表示
Cache
对象的存储。提供所有命名缓存的主目录,ServiceWorker
可以访问并维护名字字符串到Cache
对象的映射。 - 方法:
caches.open(name)
:打开一个具有指定名称的缓存。caches.keys()
:返回当前ServiceWorker
可以访问的所有缓存名称的列表。
- 功能:表示
- Client
- 功能:表示
ServiceWorker
client的作用域。一个ServiceWorker
client可以是浏览器上下文的一个文档,也可以是一个由active worker控制的SharedWorker
。
- 功能:表示
- Clients
- 功能:表示一个
Client
对象容器;是访问当前源的活动的ServiceWorker
client的主要途径。 - 方法:
clients.matchAll()
:返回一个包含所有与当前ServiceWorker
相关联的Client
对象的Promise。
- 功能:表示一个
- FetchEvent
- 功能:传递给
ServiceWorkerGlobalScope.onfetch
处理函数的参数,FetchEvent
代表一个在ServiceWorker
的ServiceWorkerGlobalScope
中分发的请求动作。它包含关于请求和响应的结果信息,并且提供FetchEvent.respondWith()
方法,这个方法允许我们提供任意的响应返回到控制页面。 - 方法:
event.respondWith(response)
:提供自定义响应。
- 功能:传递给
- ServiceWorkerRegistration
- 功能:表示
ServiceWorker
的注册。包含安装、等待和激活状态的ServiceWorker
。 - 属性:
registration.installing
:返回状态为installing
的ServiceWorker
对象。registration.waiting
:返回状态为waiting
的ServiceWorker
对象。registration.active
:返回状态为activating
或activated
的ServiceWorker
对象。
- 功能:表示
示例代码
// 注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/service-worker.js', { scope: '/' }) // 注册Service Worker脚本,设置作用域为根路径
.then((registration) => { // 注册成功
console.log('Service Worker 注册成功:', registration);
// 监听更新事件
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker) {
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
console.log('Service Worker 安装并激活成功');
if (navigator.serviceWorker.controller) {
console.log('新的 Service Worker 已激活,控制页面');
}
}
};
}
};
})
.catch((error) => { // 注册失败
console.error('Service Worker 注册失败:', error);
});
}
// Service Worker脚本 (service-worker.js)
// 监听install事件
self.addEventListener('install', (event) => {
event.waitUntil( // 确保以下Promise完成前,Service Worker保持安装状态
caches.open('v1') // 打开缓存
.then((cache) => {
return cache.addAll( // 添加资源到缓存
[
'/',
'/index.html',
'/styles/main.css',
'/scripts/main.js'
]
);
})
);
});
// 监听activate事件
self.addEventListener('activate', (event) => {
event.waitUntil( // 确保以下Promise完成前,Service Worker保持激活状态
caches.keys() // 获取所有缓存名称
.then((cacheNames) => {
return Promise.all( // 并行删除旧缓存
cacheNames.map((cacheName) => {
if (cacheName !== 'v1') { // 保留最新的缓存
return caches.delete(cacheName);
}
})
);
})
);
});
// 监听fetch事件
self.addEventListener('fetch', (event) => { // 拦截网络请求
event.respondWith( // 自定义响应
caches.match(event.request) // 尝试从缓存中获取资源
.then((response) => {
if (response) { // 如果缓存中有资源,直接返回
return response;
}
return fetch(event.request) // 如果缓存中没有,从网络获取
.then((response) => {
if (!response || response.status !== 200 || response.type !== 'basic') {
return response; // 如果请求失败或不是基本类型,直接返回
}
const clonedResponse = response.clone(); // 克隆响应对象
caches.open('v1') // 打开缓存
.then((cache) => {
cache.put(event.request, clonedResponse); // 将资源添加到缓存
});
return response; // 返回网络请求的响应
});
})
);
});
虽然手动配置Service Worker和PWA可以提供高度的自定义和控制,但这个过程可能会相当繁琐,涉及到多个步骤和细节管理。幸运的是,现代前端开发工具链中有一些工具可以简化这一流程。在这样的背景下,vite-plugin-pwa
插件应运而生,它旨在为使用Vite作为构建工具的项目提供零配置的PWA支持,从而让开发者能够轻松地将网站转变为类似应用的体验。
插件vite-plugin-pwa
vite-plugin-pwa 插件提供了以下功能:
- 自动生成Web App Manifest:插件可以自动生成
manifest.json
配置文件,并使其能够在index.html
中被引用。 - Service Worker管理:管理Service Worker的注册和更新行为,并提供与前端框架(如React、Vue)交互的方法。
- 缓存策略代码生成:通过配置文件生成缓存策略代码(
generateSW
)。
示例代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa';
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
VitePWA({
registerType: 'autoUpdate', // 注册更新模式
injectRegister: 'auto', // 控制如何在应用程序中注册 Service Worker
manifest: { // manifest.json 文件配置
name: '名字',
short_name: '绰号',
description: '描述',
theme_color: '#ffffff',
start_url: '/',
display: 'standalone',
},
workbox: {
// 预加载所有 .js, .css, .html, .ico, .png, .jpg, .svg 文件
globPatterns: ['**/*.{js,ts,css,html,ico,png,jpg,svg,bin}'],
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10MB
runtimeCaching: [
{
urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
handler: 'CacheFirst',
options: {
cacheName: 'images',
expiration: {
maxEntries: 1000, // 没有数量限制
}
}
}
]
}
}),
],
})
总结
Service Worker API和vite-plugin-pwa
插件为现代Web开发带来了革命性的变化,它们使得Web应用能够提供更接近原生应用的体验,同时保持了Web的开放性和灵活性。随着技术的不断发展,我们可以预见Service Worker和PWA将在未来的Web应用中扮演更加重要的角色。