WebSocket 需要 Service Worker 感知,才能在已安装的 PWA 中持续存活
最小化你的 PWA 不应该中断实时功能。Service Workers 让 WebSocket 持久化成为可能。
为什么 WebSocket 生命周期是安装问题
用户安装实时应用(聊天、协作、实时仪表板)时,期望它们真正实时。当 WebSocket 连接在最小化、后台或挂起时断开,应用就在「始终在线」的核心承诺上失败了。MDN 的 Service Worker API 文档 表明,Service Workers 可以在主线程挂起时维持网络上下文——这是保持基于 WebSocket 的 PWA 功能正常的关键。
失败流程:没有 Service Worker 集成时会发生什么
- 用户安装聊天应用
- 应用在主线程建立 WebSocket
- 用户最小化应用(iOS)或切换标签页(桌面)
- 浏览器节流主线程定时器
- WebSocket 在不活动超时后关闭
- 用户返回应用:没有新消息,需要重新连接
- 用户责怪应用,将其删除
成功流程:Service Worker 管理的 WebSocket 生命周期
- PWA 通过 Service Worker 建立 WebSocket
- Service Worker 即使主线程休眠也保持连接
- 新消息在 Service Worker 存储中排队
- 用户唤醒应用:消息同步瞬间完成
- 应用感觉"活着",用户保持安装
实现模式
模式 1:Service Worker 客户端路由
// 主线程中
const ws = new WebSocket('wss://api.example.com/realtime');
ws.onmessage = (event) => {
// 显示消息
};
// 更好的方式:通过 Service Worker 路由
navigator.serviceWorker.addEventListener('message', (event) => {
if (event.data.type === 'ws-message') {
// 显示来自 Service Worker 的消息
}
});模式 2:Service Worker WebSocket 管理
// Service Worker 中
let wsConnection;
self.addEventListener('message', (event) => {
if (event.data.action === 'connect') {
wsConnection = new WebSocket(event.data.url);
wsConnection.onmessage = (msg) => {
// 在 IndexedDB 中存储消息
// 通知所有客户端
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({
type: 'ws-message',
payload: msg.data
}));
});
};
}
});模式 3:后台同步用于重连
// Service Worker 中
self.addEventListener('sync', (event) => {
if (event.tag === 'websocket-reconnect') {
event.waitUntil(reconnectWebSocket());
}
});
async function reconnectWebSocket() {
// 使用指数退避尝试重连
}平台特定的 WebSocket 行为
iOS Safari
- 最小化时 WebSocket 连接被激进节流
- Service Worker 将连接延长大约 5-10 分钟
- 后台获取防止完全连接丢失
- 需要用户交互背景音频例外
Chrome/Edge(桌面)
- 标签页后台后约 30-120 秒开始 WebSocket 节流
- Service Worker 延长至约 5 分钟以上才关闭
- 资源限制时发生标签页丢弃
- 通知权限延长后台生命周期
Android Chrome
- 节流不如 iOS 激进
- Service Worker 在大多数状态下维持 WebSocket
- 省电模式仍会强制关闭
- 前台服务(通过已安装应用包装器)进一步延长
WebSocket 不是万能药
并非每个实时功能都需要 WebSocket:
- 30+ 秒间隔的更新,轮询完全够用
- 推送通知更适合高延迟、低频事件
- Server-Sent Events (SSE) 简化单向流式传输
- 周期性后台同步可以批处理离线更新
仅在这些情况下实施 WebSocket:
- 毫秒级延迟确实重要(协作、游戏)
- 需要双向同时通信
- 连接安全 / 隐私规则禁止轮询
- 用户明确期望"实时"行为
隐私和权限约束
实时连接有边缘情况:
- WebSocket 数据绕过标准缓存清除
- IndexedDB 存储的消息跨站点数据擦除持续存在
- 用户驱动的登出必须显式关闭连接
- 绕过用户代理节流可能触发隐私警告
始终提供:
- 设置中清晰的实时开关
- 实时数据使用指标
- 真正终止连接的断开按钮
- 解释持续化行为的隐私说明
测量检查清单
使用以下指标监控 WebSocket 生命周期:
- 连接持续时间(节流前)
- 唤醒后重连成功率
- 消息传递延迟(主线程 vs Service Worker)
- 持续连接的电池影响
- 启用实时后的数据使用增长
下一步
从简单的 Service Worker 重连模式开始,测量连接稳定性,然后对关键实时功能升级到完整的 Service Worker 管理的 WebSocket 路由。