关网页也不丢数据!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 个演进知识点。 - 九世師 - 博客园

JavaScript 高级特性完全指南:从 ES6 到 ES2025 的 10 个核心知识点! - 九世師 - 博客园

posted @ 2026-05-22 19:09  九世師  阅读(43)  评论(0)    收藏  举报