一、PWA 是什么?
PWA(Progressive Web App,渐进式网页应用) 不是一项单一技术,而是一套基于标准 Web 技术(HTML/CSS/JavaScript)构建、通过浏览器增强能力逐步获得接近原生 App 体验的理念与技术集合。
补充 :PWA 不是某种框架,也不是要"取代"原生 App 或小程序,其核心哲学是 渐进增强(Progressive Enhancement)------从普通网页出发,逐步叠加高级特性。
"渐进式"的两层含义
| 维度 | 含义 |
|---|---|
| 开发者视角 | 提供温和的过渡方案,无需一步到位,可逐步为站点添加离线、推送、安装等能力 |
| 技术演进视角 | 浏览器底层能力持续演进------更快的渲染、更强的设备 API、WebAssembly 等 |
PWA 的三大核心支柱
| 支柱 | 含义 | 依赖技术 |
|---|---|---|
| 可靠(Reliable) | 弱网/断网仍可加载并基本可用 | Service Worker + Cache API |
| 快速(Fast) | 秒级加载、流畅交互 | 预缓存 + 运行时缓存策略 |
| 类原生(Engaging) | 可安装到桌面、全屏运行、接收推送 | Web App Manifest + Push API |
Web 最大的优势
自由开放 + 跨平台:一套代码运行在所有设备上。这是原生 App 不具备的,也是各厂商小程序难以统一标准的痛点。
二、Web 应用 vs 原生应用:差距在哪里?
| 能力 | 原生 App | 传统 Web 应用 | PWA 解决方案 |
|---|---|---|---|
| 离线使用 | ✅ 天然支持 | ❌ 无网即瘫痪 | Service Worker + Cache API |
| 消息推送 | ✅ 系统级推送 | ❌ 页面关闭即失效 | Push API + Notification API |
| 桌面入口 | ✅ 安装到主屏幕 | ❌ 必须通过浏览器 | Web App Manifest |
| 硬件调用 | ✅ 完整权限 | ⚠️ 受限于浏览器 API | Web API(摄像头/地理/蓝牙等)持续增强中 |
| 执行性能 | ✅ 原生编译 | ⚠️ 受限于 JS 引擎 | WebAssembly 逐步缩小差距 |
三、Service Worker 核心原理
3.1 前身:App Cache 的失败
在 Service Worker 之前,W3C 曾推出 Application Cache(App Cache) 标准用于离线缓存,但其设计存在严重缺陷(如无法精确控制缓存更新、隐式行为不可预测等),最终被废弃。
补充:App Cache 已于 2020 年前后被所有主流浏览器移除,不应再使用。
3.2 Service Worker 是什么?
Service Worker 是 W3C 标准定义的一种独立于页面主线程运行的后台脚本 ,充当网页与网络之间的可编程代理层。
┌─────────────┐ ┌────────────────┐ ┌──────────────┐
│ Web 页面 │ ←→ │ Service Worker │ ←→ │ 网络 / 缓存 │
└─────────────┘ └────────────────┘ └──────────────┘
3.3 架构设计要点
| 设计决策 | 原因 |
|---|---|
| 运行在独立线程 | 避免阻塞页面主线程的渲染和 JS 执行,杜绝卡顿 |
| 无法直接操作 DOM | 与页面解耦,只能通过 postMessage 与页面通信 |
| 完全异步,禁止同步 API | 防止阻塞 Worker 线程(如不允许 localStorage、XMLHttpRequest 同步模式等) |
| 独立生命周期 | 不绑定单个页面,可同时为同源下多个页面服务 |
| 按需启停 | 浏览器在空闲时终止 Service Worker,事件触发时唤醒(节省资源) |
补充 :在 Chrome 多进程架构中,Service Worker 运行在独立的 Worker 进程或共享的 Storage/Worker 进程中,而非管理 UI 的 Browser Process。它的生命周期由浏览器内核管理,与任何单个页面/标签页解耦。
3.4 完整生命周期
Service Worker 的生命周期完全独立于网页,包含以下阶段:
注册 (Register) → 下载/解析 → 安装 (Install) → 等待 (Waiting) → 激活 (Activate) → 运行 (Active/Fetch)
阶段详解
javascript
// ===== 1. 注册(在主线程中执行)=====
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js', {
scope: '/' // 控制范围,默认为 sw.js 所在目录
}).then(registration => {
console.log('SW 注册成功:', registration.scope);
}).catch(err => {
console.error('SW 注册失败:', err);
});
});
}
javascript
// ===== sw.js 文件内容 =====
// 2. 安装阶段:预缓存关键静态资源
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('static-v1').then((cache) => {
return cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
]);
})
);
// 跳过等待,立即进入激活阶段
self.skipWaiting();
});
// 3. 激活阶段:清理旧版缓存
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter(name => name !== 'static-v1')
.map(name => caches.delete(name))
);
})
);
// 立即接管所有受控页面
self.clients.claim();
});
// 4. 请求拦截阶段:缓存优先 / 网络回退
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
if (cachedResponse) {
return cachedResponse; // 命中缓存,直接返回
}
return fetch(event.request).then((networkResponse) => {
// 可选:将新请求的响应存入缓存(运行时缓存)
return caches.open('runtime-v1').then((cache) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
});
})
);
});
关键机制说明
| 机制 | 说明 |
|---|---|
event.waitUntil() |
延长事件生命周期,确保异步操作完成前不终止 Worker |
self.skipWaiting() |
Install 完成后跳过 Waiting 阶段,不等待旧页面的标签关闭 |
self.clients.claim() |
Activate 后立即接管所有在 scope 内的页面,无需等待下一次导航 |
event.respondWith() |
接管 fetch 请求的响应,返回自定义 Response 或缓存内容 |
补充 :新注册的 Service Worker 不会立即控制已打开的页面。首次安装后,必须刷新页面 或调用
clients.claim()才能接管。这是最常见的踩坑点。
3.5 常见缓存策略
| 策略 | 逻辑 | 适用场景 |
|---|---|---|
| Cache First | 优先缓存,无则网络 | 静态资源(CSS/JS/图片) |
| Network First | 优先网络,失败回退缓存 | API 数据、频繁更新内容 |
| Stale While Revalidate | 先返缓存,同时后台更新 | 新闻、文章列表 |
| Cache Only | 仅使用缓存 | 预缓存的 Shell 页面 |
| Network Only | 仅使用网络 | 非幂等请求(POST 等) |
3.6 工程化工具:Workbox
手动编写 Service Worker 缓存逻辑容易出错,Google 推出的 Workbox 是目前最主流的工程化方案(截至 2026 年仍是):
javascript
// workbox-config.js 示例
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate, CacheFirst } from 'workbox-strategies';
// 预缓存所有构建产物(由构建工具自动注入清单)
precacheAndRoute(self.__WB_MANIFEST);
// API 请求:Stale While Revalidate
registerRoute(
({ url }) => url.pathname.startsWith('/api/'),
new StaleWhileRevalidate({ cacheName: 'api-cache' })
);
// 图片:Cache First
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({
cacheName: 'image-cache',
plugins: [{ maxEntries: 50, maxAgeSeconds: 30 * 24 * 60 * 60 }]
})
);
3.7. 普通 Web Worker vs Service Worker
| 特性 | Web Worker | Service Worker |
|---|---|---|
| 运行位置 | 渲染进程内的独立线程 | 独立的 Storage/Worker 进程 |
| 生命周期 | 与创建它的页面绑定,页面关闭即终止 | 独立于任何页面,由浏览器内核按需启停 |
| 作用域 | 仅服务于创建它的单个页面 | 可服务于同源下所有页面 |
| 持久化 | ❌ 无状态,每次重新执行 | ✅ 有状态(通过 Cache API / IndexedDB) |
四、Web App Manifest:一级入口
manifest.json(更准确应称为 Web App Manifest)是让网页可"安装"到设备桌面/主屏幕的配置文件。
4.1 HTML 引入方式
html
<head>
<link rel="manifest" href="/manifest.json">
<!-- iOS 兼容(Safari 不支持标准 Manifest 安装,需要额外 meta 标签) -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="My App">
<link rel="apple-touch-icon" href="/icons/icon-192.png">
</head>
4.2 manifest.json 核心字段
json
{
"name": "我的 PWA 应用",
"short_name": "MyApp",
"description": "一个示例 PWA 应用",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3f51b5",
"orientation": "portrait-primary",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
补充:
- 服务器须返回
Content-Type: application/manifest+json192x192和512x512两个尺寸的 PNG 图标是安装到桌面的最低要求"purpose": "any maskable"可让图标适配不同平台的裁切规则display可选值:fullscreen|standalone|minimal-ui|browser
4.3 各平台安装支持现状(2026 年)
| 平台 | 支持情况 |
|---|---|
| Chrome (Android/Desktop) | ✅ 完整支持,自动弹出安装提示 |
| Edge | ✅ 完整支持 |
| Samsung Internet | ✅ 支持 |
| Safari (iOS) | ⚠️ 不支持标准 Manifest 安装,需通过"添加到主屏幕"手动操作,且功能受限(无 Push、无 Background Sync) |
| Safari (macOS) | ⚠️ 有限支持 |
补充 :
manifest.json除了可配置图标、名称等,还需要强调 iOS Safari 至今不支持标准 Web App Manifest 的自动安装流程,这是实际开发中最大的兼容性痛点。
五、消息推送
PWA 通过 Push API + Notification API 实现服务端主动推送消息:
服务器 → 推送服务(如 FCM/VAPID)→ 浏览器推送服务 → Service Worker (push 事件) → 展示通知
javascript
// sw.js 中监听 push 事件
self.addEventListener('push', (event) => {
const data = event.data ? event.data.json() : { title: '新消息' };
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192.png',
badge: '/icons/badge-72.png'
})
);
});
// 监听通知点击
self.addEventListener('notificationclick', (event) => {
event.notification.close();
event.waitUntil(
clients.openWindow('/')
);
});
补充 :消息推送依赖 VAPID(Voluntary Application Server Identification) 协议进行身份验证。即使页面已关闭,Service Worker 仍可被推送事件唤醒并展示通知------这是 Web 应用首次获得与原生 App 同等的消息触达能力。
六、安全要求
| 要求 | 说明 |
|---|---|
| HTTPS(强制) | Service Worker 仅允许在 https:// 或 localhost(开发环境)下注册。HTTP 明文传输存在被篡改风险,而 SW 能拦截所有请求,安全是底线 |
| 同源策略 | Service Worker 只能拦截同源请求,scope 不能超出自身路径 |
| CSP(内容安全策略) | Service Worker 脚本本身受 CSP 管控,script-src 需包含 SW 文件来源 |
| 无 DOM 访问 | 无法直接操作页面 DOM,从架构上隔离了页面篡改风险 |
七、PWA 的现状与展望(2026 年视角)
已取得的进展
- 桌面端:Chrome/Edge 全面支持 PWA 安装,Windows/macOS/Linux 均可将 PWA 作为独立应用使用
- ChromeOS:PWA 是一等公民
- Workbox 成熟:工程化实现几乎零成本
- WebAssembly:计算密集型任务性能大幅提升
- Web API 持续增强:Web Bluetooth、Web NFC、WebUSB、File System Access API 等逐步铺开
仍面临的挑战
| 挑战 | 说明 |
|---|---|
| iOS 限制 | Apple 对 Safari 中 PWA 能力刻意限制(无推送/无后台同步/无自动安装),直到 iOS 16.4+ 才有限支持 Web Push,但仅限"添加到主屏幕"后的 PWA |
| 国内生态 | 微信小程序 / 快应用 / 各厂商定制系统形成壁垒,PWA 推广受阻 |
| 商业闭环 | PWA 无应用商店分发,缺乏用户获取渠道 |
| 底层能力 | 对系统级 API(通讯录、电话、短信等)的访问仍受限 |
未来关键方向
- WebGPU:GPU 加速计算与图形渲染
- WebAssembly + WASI:接近原生的执行效率
- AI 智能体与 Web 的融合:2026 Google I/O 已展示浏览器内置 AI 模型(Prompt API)
- 跨平台统一标准推进
八、总结速查表
PWA = 渐进增强理念 + Web 标准技术集合
核心技术栈:
├── Service Worker → 离线缓存 + 请求代理 + 后台任务
├── Web App Manifest → 安装到桌面 + 全屏运行
├── Push API → 服务端消息推送
├── Notification API → 系统通知展示
├── Cache API → 可编程的 HTTP 缓存层
└── HTTPS → 安全基线
Service Worker 生命周期:
Register → Install → Waiting → Activate → Fetch(运行)
工程化推荐工具:Workbox(Google 官方)
核心结论 :PWA 的真正价值不在于取代谁,而在于让 Web 应用渐进地获得更好的用户体验。决定 PWA 上限的始终是浏览器底层技术的演进------渲染效率、设备 API 支持度、WebAssembly 等。这些能力正在持续进化中。