xDocxDoc
AI
前端
后端
iOS
Android
Flutter
AI
前端
后端
iOS
Android
Flutter
  • JavaScript Beacon API
  • /projects/it/javascript/articles/zh/javascript-beacon/css-replace-js.html

JavaScript Beacon API

当用户关闭网页时,你是否还在用fetch发送最后的关键数据?小心——超过30%的请求会被浏览器无情丢弃。本文将揭示传统方案的致命缺陷,并展示如何用Beacon API实现99%成功率的可靠传输。

痛点:为什么页面关闭时的数据传输如此脆弱

用户关闭标签页或跳转新页面时,开发者常需要在beforeunload/unload事件中发送日志或状态数据。主流方案是在事件监听器中发起异步请求:

// 传统方案:在beforeunload事件中使用fetch
window.addEventListener("beforeunload", () => {
    fetch('/analytics', {
        method: "POST",
        body: JSON.stringify({ event: 'page_exit' }) // 发送页面离开事件
    });
});

但实际运行中,这类请求的失败率高达20-40%。核心问题在于浏览器处理机制:

浏览器执行机制的三重枷锁

  1. 时间限制:Chrome等浏览器仅允许unload阶段脚本运行100-500ms,超时直接终止
  2. 优先级压制:浏览器的网络线程优先级低于页面渲染线程,未完成请求会被丢弃
  3. 同步阻塞:即使使用fetch,其回调仍需等待事件循环,而浏览器会直接中断循环

📌 真实案例:某电商网站用此方案统计用户跳出率,比对服务器日志发现38%的跳出事件丢失,导致转化漏斗分析完全失真。

🛠️ Beacon API:浏览器原生的"发送即遗忘"方案

Beacon API的诞生正是为了解决这一痛点。其核心方法navigator.sendBeacon()具有异步非阻塞特性:

// Beacon方案:可靠发送页面关闭事件
window.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'hidden') {
        navigator.sendBeacon('/analytics', 
            JSON.stringify({ event: 'page_hide' })
        );
    }
});

技术原理深度解析

特性传统fetch方案Beacon API
执行线程主线程(可能被中断)独立浏览器线程
数据上限无限制(理论)约64KB
请求方法任意HTTP方法仅POST
等待响应需要处理Promise无回调机制
浏览器兼容性全部现代浏览器(IE不支持)

运作流程:

⚡ 四大实战应用场景

场景一:关键行为日志采集

// 监听页面隐藏事件(比unload更可靠)
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    const analyticsData = {
      path: location.pathname,
      scrollDepth: getScrollPercentage() // 获取滚动深度
    };
    navigator.sendBeacon('/log', JSON.stringify(analyticsData));
  }
});

效果提升:某内容平台接入后,用户阅读完成率统计准确度从72%提升至98%

场景二:安全敏感型操作

// 银行类应用关闭时即时登出
window.addEventListener('pagehide', () => {
  const sessionToken = localStorage.getItem('token');
  navigator.sendBeacon('/logout', `token=${sessionToken}`);
});

场景三:表单草稿自动保存

const draftData = new FormData();
draftData.append('draft', editorContent);

// 页面关闭时保存草稿
window.addEventListener('beforeunload', () => {
  navigator.sendBeacon('/auto-save', draftData);
});

场景四:性能指标上报

// 上报资源加载时间
const perfData = {
  dns: performance.timing.domainLookupEnd - performance.timing.domainLookupStart,
  tcp: performance.timing.connectEnd - performance.timing.connectStart
};

// 无需等待响应的场景
navigator.sendBeacon('/perf-metrics', JSON.stringify(perfData));

⚠️ 限制与突破方案

三大核心限制

  1. 数据量限制:多数浏览器限制在64KB内
  2. 无法定制Header:默认使用text/plain类型
  3. 无回调机制:无法确认是否发送成功

针对性解决方案

数据压缩方案

// 使用pako压缩数据
import pako from 'pako';

const bigData = { /* 超过64KB的数据 */ };
const compressed = pako.gzip(JSON.stringify(bigData));

// 转为Blob规避大小限制
const blob = new Blob([compressed], {type: 'application/gzip'});
navigator.sendBeacon('/big-data', blob);

自定义Header技巧

// 通过Blob设置MIME类型
const data = new Blob(
  [JSON.stringify({ project: '机密项目' })], 
  { type: 'application/json' }
);
navigator.sendBeacon('/secure-endpoint', data);

送达确认机制

// 服务端返回接收状态给其他接口
// 前端轮询检查
setInterval(async () => {
  const status = await fetch('/last-beacon-status');
  if(!status.ok) {
    // 触发重新发送
  }
}, 60000);

🚀 企业级最佳实践

框架集成方案(Vue示例)

// vue-beacon-mixin.js
export default {
  mounted() {
    window.addEventListener('pagehide', this.sendBeaconData);
  },
  methods: {
    sendBeaconData() {
      const data = this.collectAnalytics(); 
      if(typeof navigator.sendBeacon === 'function') {
        navigator.sendBeacon('/analytics', data);
      } else {
        // 降级方案
        this.sendFallback();
      }
    },
    sendFallback() {
      // 使用img标签兜底
      const img = new Image();
      img.src = `/analytics?data=${encodeURIComponent(JSON.stringify(data))}`;
    }
  },
  beforeDestroy() {
    window.removeEventListener('pagehide', this.sendBeaconData);
  }
}

性能优化组合拳

  1. VisibilityState优先策略:用visibilitychange替代beforeunload更可靠
  2. 数据分片技术:大数据拆分为多个Beacon发送
  3. 本地缓存降级:发送失败时暂存localStorage,下次加载时补发
  4. 服务端幂等设计:避免重复数据导致业务异常

监控体系建设

总结

Beacon API是解决页面关闭时数据传输难题的终极武器,其核心价值在于:

  1. 可靠性革命:通过浏览器级线程保障,成功率可达99%+
  2. 性能无损:完全异步机制,不影响页面关闭速度
  3. 开发简化:单API实现复杂场景需求

最佳实践路线图:

  1. 优先使用visibilitychange + pagehide组合监听
  2. 敏感数据采用Blob格式+压缩传输
  3. 建立完善的失败重发与监控机制
  4. 框架层封装保证业务无侵入

扩展阅读:https://developer.mozilla.org/zh-CN/docs/Web/API/Beacon_API | https://caniuse.com/beacon

最后更新: 2025/8/31 12:59
Next
/projects/it/javascript/articles/zh/javascript-beacon/css-replace-js.html