最近接手一个移动端H5项目,用户频繁反馈"页面点了没反应""提交按钮卡半天"。排查到最后,十有八九是用户网络断了,前端却一脸无辜地转圈。我们写接口请求时都会处理loading、超时、错误回调,但很少有人认真想过一个问题——用户断网了,你的前端代码知道吗?
前端要检测网络状态,绕不开 navigator.onLine 和 online/offline 事件。这俩东西在面试题里出现频率不低,实战项目里真正用好的却不多。今天把这套方案的原理、代码、坑位一次讲透,看完你不仅能写出一个能用的网络状态模块,还能在项目评审时说清楚为什么这么设计。
1. 网络状态检测藏着的真实业务需求
1.1 不是所有断网场景都需要前端插手
先泼一盆冷水:如果你的项目只是管理后台,用户都在办公室连Wi-Fi,网络状态检测的优先级可以很低。因为断网概率小,即便断了,刷新页面多半也能解决。这时候做一套复杂的网络状态系统,属于过度设计。
但下面这些场景,网络状态检测就是刚需:
- H5电商/支付流程:用户下单时断网,表单提交失败,需要明确提示"网络异常",而不是让用户干等超时,然后重复提交造成重复订单。
- 在线文档/笔记/协同编辑:断网时本地编辑内容不能丢,需要在网络恢复后自动同步。
- 音视频/直播类页面:断网要快速切换备播流、降清晰度或显示"直播已断开"。
- 离线优先(Offline First)应用:比如PWA应用,断网时切到本地缓存数据,恢复后重新拉取。
- 弱网环境的WebView内嵌页面:扫码点餐、智慧停车这类场景经常在地下车库、电梯里操作,网络忽好忽坏。
这些场景的共同点是:断网导致的后果不可接受,且用户不会主动去刷新页面。所以前端需要主动感知网络变化,并给出对应反馈。
1.2 从"超时兜底"升级为"主动感知"
很多团队处理网络异常只有一招:接口请求失败时 catch 住,弹个Toast说"网络异常"。
这种做法最大的问题是滞后。你只能在请求发出并失败之后才知道网络有问题,而且这个失败可能因为服务器500、接口404等原因产生,这时提示"网络异常"反而是误导。
网络状态检测把"事后catch"升级成了"事前感知"。当浏览器告诉你"你现在离线",前端可以立即:
- 停止发起新的网络请求,减少无效流量和用户等待
- 明确展示"已离线"状态,而非假装还能用
- 启用本地缓存,允许用户继续浏览已加载的内容
这种体验差异,就像导航断网时,一个直接显示"当前无网络连接",另一个等你在路口转弯半天后怒吼"偏航"。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. navigator.onLine到底检测了什么
2.1 它的判定逻辑比你想的要"粗糙"
navigator.onLine 返回的是一个布尔值。所有主流浏览器都实现了这个属性,但它对"在线"的定义非常宽松——浏览器只要能访问到本地网络(local network),就认为你在线,注意不是互联网(Internet)。
举个例子:办公室路由器本身没插外网网线,但你的电脑连上了路由器。此时 navigator.onLine 返回 true。你的网页能加载出来是因为有本地缓存或者资源本来就加载完了,但任何需要访问外网的请求都会失败。
反过来,移动端断网时,很多浏览器也会把 onLine 置为 false,但Android WebView里却经常出现断网后 onLine 依然是 true 的情况。我实际测过几个国产安卓机自带的浏览器内核,在Wi-Fi信号消失后,有的需要等30秒到1分钟才更新状态。
2.2 不同平台上的表现差异
| 环境 | 断网时 onLine 变化 | 备注 |
|---|---|---|
| Chrome 桌面 | 快速变为 false,恢复后很快回到 true | 以太网/无线断开会立即触发 offline 事件 |
| Firefox 桌面 | 同上,表现较稳定 | 不影响主线程 |
| iOS Safari / WKWebView | 断网后状态更新偏慢,有时会一直保持 true | 建议配合主动探测 |
| Android Chrome | Wi-Fi断开后变化较快,但网络类型切换时不稳定 | 4G切Wi-Fi容易误报 offline |
| Android WebView (部分国产壳) | 可靠性最差,经常不触发事件 | 必须配备心跳探测 |
因为 navigator.onLine 的实现依赖于浏览器的网络状态监听机制,而浏览器对"网络接口"的检测颗粒度跟实际互联网连通性是两码事。所以这个属性只能作为辅助信号,不能当作唯一判定依据。
2.3 移动端为什么特别不可靠
移动端网络变化频繁,比如电梯里信号消失、从4G切到Wi-Fi、地铁隧道里短暂断网。系统层面的网络切换时机、WebView 对网络状态回调的延迟,都会导致 navigator.onLine 的状态发生变化的速度跟不上真实情况。
实测中常见的现象:
- 断网后
offline事件根本没有触发,但接口请求已经全部超时 - WiFi切换网络时,触发了
offline又立刻触发online,造成闪烁 - 应用退到后台再回前台,状态是旧的,需要重新探测
所以结论是:navigator.onLine + online/offline 事件只能作为基础信号,要做出稳定的网络状态检测,还需要主动探测兜底。
3. online/offline事件:触发机制和实际行为细节
3.1 事件类型与绑定方式
浏览器在检测到网络状态变化时,会往 window 对象上派发 online 和 offline 事件。绑定方式有三种:
javascript复制// 方式一:addEventListener(推荐)
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
// 方式二:直接赋值(不推荐,会覆盖其他监听)
window.ononline = handleOnline;
window.onoffline = handleOffline;
// 方式三:在 body 元素上监听(不推荐,事件目标不同,行为不一致)
document.body.ononline = handleOnline;
注意:事件挂在 window 上,不要写到 document 上去监听,否则部分浏览器不触发。
3.2 事件触发顺序
当网络状态变化时,浏览器通常会先更新 navigator.onLine 的值,然后派发事件。顺序大概是:
- 网络断开或恢复
- 浏览器底层网络状态更新
navigator.onLine变化- 对应事件派发到
window
但这里有个细节:事件触发不保证100%可靠。有些低端安卓手机在熄屏后网络断开,回前台不会触发 offline;WebView里
