网络状态监听与事件驱动:online/offline事件、navigator.onLine、重连检测
网络状态感知是离线同步的起点。UI 需要在网络中断时立即切换为离线模式,在网络恢复时触发数据回传与 UI 更新。本章讲解浏览器原生网络事件与 navigator.onLine 的准确含义、典型陷阱以及重连检测策略。
3.1 浏览器网络状态 API 概览
| API / 属性 | 类型 | 特点 | 局限性 |
|---|---|---|---|
window.addEventListener('online', fn) |
事件 | 浏览器认为网络可用时触发 | 不一定代表真实可达性 |
window.addEventListener('offline', fn) |
事件 | 浏览器认为网络断开时触发 | Wi-Fi 连接但无外网时可能不触发 |
navigator.onLine |
属性(布尔) | 实时读取当前网络状态 | 仅反映本地连接,非端到端连通性 |
navigator.connection (Network Information API) |
对象 | 提供连接类型、下行速度、RTT 等 | 非标准、Chrome 为主,兼容性较差 |
核心认知:
online/offline 事件与 navigator.onLine 只能检测“本地网络接口是否可用”,不能代表“服务端是否可达”。对于离线同步场景,必须配合心跳探测或业务请求超时作为补充。
3.2 事件驱动架构:注册与取消
以下代码展示在 Vue 3 Composition API 中注册网络事件监听,并利用 onUnmounted 完成清理,避免内存泄漏。
import { ref, onMounted, onUnmounted } from 'vue'
const isOnline = ref(navigator.onLine)
function handleOnline() {
isOnline.value = true
console.log('[Net] 网络恢复')
// 触发离线队列同步
syncOfflineQueue()
}
function handleOffline() {
isOnline.value = false
console.log('[Net] 网络断开')
// UI 切换为离线模式
enterOfflineMode()
}
onMounted(() => {
window.addEventListener('online', handleOnline)
window.addEventListener('offline', handleOffline)
})
onUnmounted(() => {
window.removeEventListener('online', handleOnline)
window.removeEventListener('offline', handleOffline)
})
注意:
navigator.onLine 的初始值应在页面加载时立即读取,因为 online/offline 事件在连接状态变化时才会触发,首次加载可能错过。
3.3 navigator.onLine 的常见陷阱
- 操作系统差异: macOS 下 Wi-Fi 连接但无互联网时,Chrome 可能仍返回
true;Android 下断开移动数据后通常会正确返回false。 - 浏览器兼容: 部分老旧浏览器(IE 9 以下)不支持
navigator.onLine,需要降级为定时探测。 - 304 / DNS 缓存: 即便网络已断开,浏览器可能因缓存未失效而短暂认为在线。
- 事件重复触发: 网络状态频繁切换时,
online/offline可能连续触发多次,需要防抖处理。
3.4 重连检测策略
仅靠原生事件无法满足离线同步的可靠性要求,通常需要结合以下策略实现更精准的重连检测:
- 心跳探测: 定期向服务端发送 HEAD 或 GET 请求(例如每 10s),若连续 n 次超时则判定离线。
- 业务请求回退: 使用
fetch或axios的timeout配置,将超时视为离线,触发队列暂存。 - 指数退避重试: 重连失败后,等待时间依次增加(1s、2s、4s、8s…),避免高频无效请求。
- 优先级队列: 恢复连接后,按数据重要性依次同步,先同步元数据(如 刷新),再同步业务数据。
3.5 流程图:网络状态变化与 UI 响应
3.6 调试与验证方法
- 浏览器 DevTools Network 面板: 勾选 Offline 复选框模拟网络断开,观察事件触发情况。
- Chrome DevTools 的 Network conditions: 可模拟不同网络类型(3G、慢速 4G)以及离线状态。
- 控制台日志: 在
handleOnline/handleOffline中加入console.timeStamp(),精确记录事件发生时刻。 - 自定义离线测试页: 使用
window.dispatchEvent(new Event('offline'))手动触发事件,验证 UI 响应逻辑。
3.7 常见错误与优化
| 常见错误 | 现象 | 解决方案 |
|---|---|---|
| 未移除事件监听 | 页面卸载后仍触发回调,后台产生冗余网络请求 | 在 beforeUnmount / onUnmounted 中调用 removeEventListener |
| 频繁触发同步 | 网络恢复瞬间多次触发 online 事件,导致数据重复同步 | 加入防抖(debounce)或节流(throttle),例如 2s 内只同步一次 |
| 仅依赖原生事件 | 用户计算机休眠唤醒后事件不触发,导致“假在线” | 开启定时心跳检测(如每 10s 一次),作为事件机制的补充 |
| 同步顺序混乱 | 先同步大数据造成小数据延迟 | 设计优先级队列,先同步鉴权、元数据,再同步业务数据 |
性能考量: 心跳探测间隔不宜过短,建议不少于 5s,避免频繁请求消耗电量与带宽。移动端可用
navigator.connection.onchange 事件触发更精细的网络变化检测,但需确认浏览器兼容性。