背景
用户离开页面时, 浏览器会取消正在发出的异步请求。这是因为默认情况下,异步请求是非阻塞的。一旦请求被放入队列中,网络请求交给浏览器的网络线程 (网络线程不会阻塞 JS 线程)。这意味着当页面进入 "终止" 状态时, 它们可能被销毁。 那究竟有方案能够保证页面刷新前接口的调用么?
方案
方案1: navigator.sendBeacon()
(最佳实践)
javascript
// 监听页面卸载事件(刷新/关闭)
window.addEventListener('beforeunload', () => {
const data = JSON.stringify({ event: 'refresh', time: Date.now() });
navigator.sendBeacon('/api/log', data);
});
优势:
- 专为页面卸载场景设计
- 不阻塞页面卸载过程
- 能处理大容量数据(现代浏览器支持最高64KB)
- 自动处理内容类型(可发送Blob/字符串)
参考 MDN 的介绍

方案2:使用 fetch()
+ keepalive
javascript
window.addEventListener('beforeunload', async () => {
try {
await fetch('/api/log', {
method: 'POST',
body: JSON.stringify({ action: 'page_refresh' }),
keepalive: true, // 关键参数
headers: { 'Content-Type': 'application/json' }
});
} catch (e) {
console.error('请求失败,但页面已卸载', e);
}
});
注意事项:
- 仅适用于 Chrome/Edge(Firefox 不支持)
- 请求头受限(无法设置
Content-Length
等) - 响应不可读取(设计上只保证发送)
最终选择方案 2 实现需求。