关网页也不丢数据!sendBeacon埋点可靠方案!
各位玩家朋友,大家好!我是King。
今天咱们聊一个很实在的问题:你做的用户行为埋点,是不是经常在用户关掉页面那一刻,数据就“蒸发”了?
别急,我来给你说清楚怎么用 navigator.sendBeacon 把这个坑填上。
一、关掉页面,数据为啥容易丢? https://www.kfzhan.com/kfxx/301.html https://www.kfzhan.com/kfxx/300.html
很多朋友习惯用 ajax 或 fetch 在页面关闭前发请求。比如:
window.addEventListener('beforeunload', () => {
fetch('/api/track', {
method: 'POST',
body: JSON.stringify(data)
});
});
看着没毛病,但实际跑起来,十次里有三四次请求根本发不出去。为什么?
因为页面关闭时,浏览器会终止所有还在处理中的异步操作。fetch 请求还没发完,页面已经没了,数据自然就丢了。
二、sendBeacon 是什么?能解决什么问题?
navigator.sendBeacon 是浏览器专门为“页面关闭时发数据”这个场景设计的接口。它的特点就三个:
数据一定会发出去——页面关不关不影响 https://www.kfzhan.com/kfxx/299.html https://www.kfzhan.com/kfxx/298.html
不阻塞页面关闭——发数据的同时页面直接关,用户感觉不到卡顿
请求量小——适合埋点这类非核心但重要的数据 https://www.kfzhan.com/bbdq/297.html https://www.kfzhan.com/bbdq/296.html
简单说:你告诉浏览器“帮我把这点数据发出去”,然后该关页面关页面,浏览器在后台默默帮你发完。
三、怎么用?代码直接贴给你
// 收集用户行为数据
function sendTrack(eventType, extraData = {}) {
const data = {
event: eventType, // 比如 'click'、'scroll'、'page_close'
time: Date.now(),
url: window.location.href,
...extraData
};
// 关键:用 sendBeacon 发送
const success = navigator.sendBeacon(
'/api/track', // 你的埋点接口地址
JSON.stringify(data) // 数据转成字符串
);
if (!success) {
// 万一队列满了,降级用 fetch(但一般很少发生)
fetch('/api/track', {
method: 'POST',
body: JSON.stringify(data),
keepalive: true // 这个也能保活,但 sendBeacon 更稳
});
}
}
// 页面关闭时调用
window.addEventListener('beforeunload', () => {
sendTrack('page_close', { stayTime: getPageStayTime() });
});
// 普通点击也能用
button.onclick = () => sendTrack('click_submit');
四、三个容易踩的坑
坑1:数据量别太大
sendBeacon 一般限制 64KB 左右。你要是把用户完整操作日志(几 MB)塞进去,浏览器直接拒绝。埋点数据只记关键字段:事件类型、时间戳、必要参数。
坑2:只能用 POST 方法 https://www.kfzhan.com/bbdq/295.html https://www.kfzhan.com/bbdq/294.html
不支持 GET、PUT 等。你的后端接口得按 POST 接收。
坑3:不是所有浏览器都完美支持
主流浏览器(Chrome、Firefox、Safari、Edge)都没问题。老项目如果还在支持 IE,需要做降级:
const sendData = navigator.sendBeacon
? (url, data) => navigator.sendBeacon(url, data)
: (url, data) => {
// 降级用同步 XMLHttpRequest(不推荐,但比丢数据强)
const xhr = new XMLHttpRequest();
xhr.open('POST', url, false);
xhr.send(data);
};
五、什么场景最适合用 sendBeacon?
页面关闭/刷新:统计用户停留时长、跳出率
链接跳转:用户点了外链,要记录这次跳转 https://www.kfzhan.com/bbdq/293.html https://www.kfzhan.com/bbdq/292.html
浏览器切后台:visibilitychange 事件配合 sendBeacon
滚动深度:用户滚动到底部,关页面之前发最后一次
六、完整示例:一个靠谱的埋点小工具
const Tracker = {
// 队列
_queue: [],
// 发送
send(eventName, data = {}) {
const payload = {
event: eventName,
time: Date.now(),
path: location.pathname,
...data
};
// 页面可见时,可以用普通请求(更灵活)
if (document.visibilityState === 'visible') {
fetch('/api/track', {
method: 'POST',
body: JSON.stringify(payload),
headers: { 'Content-Type': 'application/json' }
}).catch(e => console.warn(e));
} else {
// 页面不可见或关闭时,用 sendBeacon
navigator.sendBeacon('/api/track', JSON.stringify(payload));
}
}
};
// 页面关闭
window.addEventListener('beforeunload', () => {
Tracker.send('page_close', { stayTime: performance.now() });
});
// 使用
Tracker.send('click_button', { buttonName: 'submit' });
七、总结一下
navigator.sendBeacon 不是什么新技术,但很多朋友要么不知道,要么用错了地方。记住三句话:
页面关闭时数据发不出去?换成 sendBeacon
数据量别超 64KB,只记关键信息 https://www.kfzhan.com/bbdq/291.html https://www.kfzhan.com/bbdq/289.html https://www.kfzhan.com/bbdq/290.html
做个降级兜底,保数据不丢
做埋点,最怕的不是数据多,而是数据丢了你自己还不知道。用对工具,关页面也不怕。
希望这篇文章对你有帮助。我是King,咱们下期见! https://www.kfzhan.com/bbdq/288.html https://www.haomir.com.cn/xkcq/347.html
原创内容,转载注明出处。欢迎评论区交流你的埋点经验。
更多交流经验文章放在以下链接了:
JS异步四兄弟成长记:9个关键升级让你少写回调! - 九世師 - 博客园
异步编程完全指南:从 Promise 到 await 与 Async 迭代器的 8 个演进知识点。 - 九世師 - 博客园

浙公网安备 33010602011771号