表单提交前应通过 fetch 探测请求(如 head /favicon.ico)判断真实网络连通性,而非依赖不可靠的 navigator.online;提交时需 preventdefault() 并将序列化数据暂存 localstorage,键名带时间戳或 uuid;重发应在用户下次交互时触发,配合重试次数限制与成功清理;页面卸载前仅能同步标记,关键暂存必须提前完成。

表单提交前怎么检测网络是否断开
浏览器本身不提供“实时网络状态”API,navigator.onLine 只反映浏览器是否认为自己在线(比如 Chrome 在离线模式下会返回 false,但实际网络恢复后它可能仍缓存旧值),不能可靠判断真实连通性。
更实用的做法是:在提交前发一个轻量探测请求(如 HEAD 到自身域名的 /health 或 /ping 端点),超时或失败即视为断网。
- 不要依赖
navigator.onLine做唯一判断,它在多数真实断网场景下返回true - 探测请求必须用
fetch并设置timeout(通过AbortController),否则卡住 UI - 探测地址建议用同源静态路径(如
/favicon.ico),避免跨域或后端逻辑干扰 - 如果后端已支持 Service Worker,可让其接管探测,但普通表单无需强依赖 SW
submit 事件里如何暂停并降级为本地暂存
原生 submit 事件默认会跳转或刷新页面,必须用 event.preventDefault() 阻止,再手动控制后续流程。断网时不能丢数据,得存在 localStorage 或 IndexedDB —— 但注意 localStorage 有同源限制和容量上限(通常 5–10MB),且是同步阻塞操作。
- 在
form.addEventListener('submit', handler)中立即调用event.preventDefault() - 用
JSON.stringify()序列化表单字段(推荐用new FormData(form)转对象再序列化) - 键名建议带时间戳或 UUID,避免多表单覆盖,例如
localStorage.setItem('offline-form-20240520-abc123', data) - 不要存
<input type="file">的文件二进制内容,只存文件名、类型、最后修改时间等元信息
重新联网后怎么自动重发暂存的表单
自动重发不是“一连上网就狂发”,而是需要明确触发时机 + 可控重试策略。常见错误是监听 online 事件后立刻发请求,但此时页面可能还没完成资源加载,或用户正切到其他 Tab,导致请求被 abort。
立即学习“前端免费学习笔记(深入)”;
- 监听
window.addEventListener('online', ...)是起点,但仅作“通知”,不直接发请求 - 真正重发建议放在用户下次主动交互时(比如点击按钮、切换 Tab 回来、或定时器检查 3 秒后)
- 每条暂存记录应包含重试次数字段,超过 3 次失败就标记为“永久失败”,避免无限循环
- 重发成功后必须用
localStorage.removeItem()清理,否则重复提交 - 后端需幂等设计(比如用
X-Request-ID去重),因为前端无法保证“只发一次”
用户没等到重发就关闭页面怎么办
页面卸载前只有极短窗口(约 50ms)执行同步逻辑,beforeunload 和 unload 事件中禁止异步操作(如 fetch),也禁止弹窗。所以“关页前发请求”不可行。
- 所有关键暂存操作必须在用户输入时或提交触发时完成,不能拖到卸载阶段
- 可在
beforeunload里设个标记(如sessionStorage.setItem('pending-offline-submit', 'true')),下次打开时检查并提示“检测到未发送的表单” - Service Worker 能在后台持续运行,但普通表单不强制要求它;若已接入,可用
backgroundFetch或消息通道唤醒重发逻辑 - 最现实的兜底:把暂存逻辑封装成独立函数,确保每次表单变更都调用一次,而不是只靠提交那一刻











