navigator.online不可靠,需结合初始化探测、online事件监听、轻量心跳及indexeddb队列四环节协同实现可靠同步。

navigator.onLine 本身不能“触发同步”,它只提供瞬时状态快照;真正能触发同步的是 online 事件,但必须配合手动初始检查 + 后台队列机制,否则上线那一刻的同步会丢失。
为什么直接监听 online 事件还不够
浏览器不会在页面加载完成时主动触发 online 或 offline 事件——哪怕用户是离线打开页面,window.addEventListener('online', ...) 也永远不会被调用。这意味着:如果用户首次加载就处于离线状态,后续网络恢复时你确实能收到 online 事件;但如果用户一开始就是在线的,之后断网再重连,而你又没在初始化时检查过当前状态,那么第一次同步逻辑可能就漏掉了。
更关键的是:navigator.onLine 返回 true 不代表能连通你的后端(比如 WiFi 通但防火墙拦了 API 域名),所以仅靠它判断是否“可同步”风险很高。
- 页面加载后必须立即执行一次
navigator.onLine检查,并根据结果决定是否要“补跑”同步逻辑 -
online事件只响应系统级连接变化(如拔网线、关 WiFi),对 DNS 失败、服务不可达等场景完全无感 - 若同步任务耗时较长(如批量上传 IndexedDB 中的草稿),应避免阻塞 UI,推荐用
requestIdleCallback或 Web Worker 调度
如何安全地注册并响应 online 事件
监听本身很简单,但容易踩内存泄漏和重复绑定的坑。不要在每次组件挂载时无条件 addEventListener,尤其在 React/Vue 的热更新或路由复用场景下。
正确做法是封装一个可销毁的监听器,确保只绑定一次,并在合适时机清理:
let onlineHandler = null;
function setupOnlineListener() {
if (onlineHandler) return;
onlineHandler = () => {
// 这里不直接执行同步,而是触发队列处理
handleSyncQueue();
};
window.addEventListener('online', onlineHandler);
}
function teardownOnlineListener() {
if (onlineHandler) {
window.removeEventListener('online', onlineHandler);
onlineHandler = null;
}
}
- 避免在
useEffect或mounted中反复注册,应全局单例管理 - 不要在事件回调里直接调用
fetch—— 应交由统一的同步队列函数(如handleSyncQueue)调度 - 移动端 WebView(如微信内置浏览器)对
online事件支持不稳定,需降级为定时心跳探测
同步队列怎么设计才不丢数据
离线期间产生的操作(如表单提交、评论发送)必须先持久化到 IndexedDB,而不是内存或 localStorage;否则刷新页面就清空了。
典型结构包含字段:id(自增主键)、type(如 "POST_COMMENT")、payload(序列化后的请求体)、timestamp、retries(失败重试次数)。同步成功后,必须在事务中删除对应记录。
- 使用
IndexedDB而非localStorage:前者支持事务、大容量、结构化数据,后者仅字符串且无原子性 - 同步函数应按顺序逐条处理,每条失败后更新
retries并延迟重试(如指数退避),避免雪崩式请求 - 同步前建议加一次轻量心跳(如
fetch('/health', { method: 'HEAD', cache: 'no-store' })),超时即跳过本次同步,防止发出去全 503
容易被忽略的初始化陷阱
最常出问题的地方不是事件监听,而是页面刚打开时的状态误判。例如:
用户用 Chrome 离线打开 PWA,navigator.onLine 在某些版本中仍返回 true(尤其有 Service Worker 缓存时);或者 Safari 在飞行模式下首次读取为 false,但几秒后又变成 true——这会导致你误以为已联网而跳过离线 UI 初始化。
- 必须在
DOMContentLoaded后立刻执行一次真实连通性探测(哪怕只是fetch('/')加 2s 超时) - 把初始状态、事件监听、心跳探测三者结果做“与”判断:只有三者都确认在线,才认为可同步
- 不要依赖
online事件来“开启轮询”或“恢复定时任务”——这些行为应在初始化阶段就基于探测结果决定
真正可靠的同步,从来不是靠一个布尔值驱动的,而是由初始化探测、事件响应、队列持久化、失败回退四个环节咬合而成。少任何一个,都会在弱网或极端切换场景下丢数据。










