Skip to main content

埋点与数据上报

面试题:前端埋点有哪几种方案?上报用什么方式?

埋点用于采集用户行为(PV/UV、点击、曝光、停留时长),是数据分析和监控的基础。

三种埋点方案

方案做法优点缺点
手动埋点(代码埋点)在业务代码里手动调用 track(event, data)精准、可带业务参数侵入业务、工作量大、易漏埋
声明式埋点在元素上加 data-track 属性,统一监听代理半自动、解耦仍需标注
无埋点(全埋点)全局监听所有点击/曝光,自动采集无需开发、可回溯数据量大、噪音多、难带业务语义
<!-- 声明式埋点:事件委托统一处理 -->
<button data-track="buy_click" data-track-id="123">购买</button>
<script>
document.addEventListener("click", (e) => {
const el = e.target.closest("[data-track]");
if (el) track(el.dataset.track, { ...el.dataset });
});
</script>

曝光埋点

「元素进入视口才算曝光」,用 IntersectionObserver 实现,避免滚动监听的性能问题:

const io = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
track("exposure", { id: entry.target.dataset.trackId });
io.unobserve(entry.target); // 只上报一次
}
});
});
document.querySelectorAll("[data-exposure]").forEach((el) => io.observe(el));

上报方式

面试题:为什么埋点上报优先用 sendBeacon?

方式特点
navigator.sendBeacon首选。异步、不阻塞页面卸载,浏览器后台发送,unload/visibilitychange 时也能成功送达
new Image().src='...'兼容性好、无跨域预检(CORS preflight),但只能 GET、数据量受 URL 长度限制
fetch(url, { keepalive: true })页面卸载也能发,可 POST 大数据
普通 XHR/fetch页面卸载时可能被中断,不适合离开类事件
function report(data) {
const body = JSON.stringify(data);
if (navigator.sendBeacon) {
navigator.sendBeacon("/log", body);
} else {
fetch("/log", { method: "POST", body, keepalive: true });
}
}

上报时机与优化

  • 离开页面上报:用 visibilitychangehidden 时)比 beforeunload/unload 更可靠(移动端 unload 常不触发)。
  • 批量 + 节流:把多条事件攒到队列里,定时或满 N 条批量发送,减少请求数;页面隐藏时 flush 剩余队列。
  • 空闲上报:非关键埋点用 requestIdleCallback 在空闲时发,不抢占主线程。
  • 关键参数:用户/设备 id、时间戳、页面 url、来源、SPA 路由变化(监听 history/hashchange 上报 PV)。