keepalive: true 不能保证页面关闭后请求送达,仅是尽力而为的提示;它要求同步调用、支持 post/put/delete、body 已序列化且≤64kb,无回调,chrome/firefox 支持,safari 不稳定;关键埋点应优先用 sendbeacon 或提前上报。

这是个常见误解——很多人以为加了 keepalive: true 就能“后台可靠发请求”,但事实是:它只是个尽力而为的提示,不是可靠通道。
keepalive 的真实作用与限制
keepalive 是一个 hint(提示),不是承诺。当页面触发 beforeunload 或 pagehide 时,浏览器会暂停大部分 JS 执行和网络活动。设置了 keepalive: true 的 fetch 请求会被放入一个“卸载期间可继续发送”的队列,但:
- Chrome 和 Firefox 支持该特性,Safari 目前(截至 2024)基本不支持或行为不稳定
- 请求必须是简单请求(如 GET/POST + 纯文本/JSON,无自定义 header),否则可能被忽略
- 请求体不能过大(通常建议 ≤ 64KB),否则可能被截断或丢弃
- 没有响应回调,无法知道是否真正发出或送达(
fetch(...).then(...)在卸载后不会执行)
正确使用 keepalive 发送埋点的写法
适合在页面卸载前(如 beforeunload 或 visibilitychange)触发一次轻量埋点:
window.addEventListener('beforeunload', () => {
fetch('/log', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ event: 'page_exit', time: Date.now() }),
keepalive: true // ✅ 关键:启用尽力发送
});
});
注意:不要 await fetch,也不要依赖 .then/.catch —— 卸载时事件循环已冻结,Promise 不会 resolve。
更可靠的埋点替代方案
如果埋点数据关键(如转化、支付完成),仅靠 keepalive 风险太高,推荐组合策略:
- 提前主动上报:在用户操作完成(如点击提交、播放结束)时立即发请求,而非等到页面关闭
- 利用 navigator.sendBeacon():专为卸载场景设计,支持二进制/FormData,兼容性更好(IE11+,所有现代浏览器),且更稳定
- 服务端兜底:前端上报失败时,结合客户端本地缓存(IndexedDB)+ 下次启动时补报
- 心跳 + 离线队列:对高价值事件,用 Service Worker 拦截并排队,在网络恢复后重试
sendBeacon 示例(比 keepalive 更推荐)
它不依赖 Promise,不占用主线程,浏览器保证在卸载前发出(只要数据不大于 64KB):
window.addEventListener('beforeunload', () => {
const data = new Blob([JSON.stringify({ event: 'leave', url: location.href })], {
type: 'application/json'
});
navigator.sendBeacon('/log', data); // ✅ 更可靠的选择
});
总之,keepalive 是一个轻量辅助手段,适用于非关键、低频的页面停留/退出埋点;关键数据务必提前上报或改用 sendBeacon + 后台重试机制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











