首屏指标必须用performanceobserver采集,不可手动打点;全局上下文挂载到标签;上报必须用navigator.sendbeacon;曝光检测用intersectionobserver;上下文需初始化时快照。

首屏指标必须用 PerformanceObserver 而不是手动打点
手动在 window.onload 或 DOMContentLoaded 里记录时间,根本不能代表用户看到内容的真实时机。FCP、LCP 这类指标浏览器内部才掌握,JS 无法靠 DOM 状态推断——比如一张大图还没 decode 完,img.onload 已触发,但 LCP 还没发生。
实操建议:
- 只用
PerformanceObserver订阅'largest-contentful-paint'、'first-contentful-paint'、'layout-shift'等 entryTypes,别自己算 - 监听必须在页面早期执行(如
内 inline script),否则可能错过首批 entry - 每个指标只上报一次:用
entry.isFinal === true过滤,避免重复上报(LCP 在页面加载中可能多次更新) - 不要用
performance.getEntriesByName()补漏——它只能查已触发的 entry,错过就永远丢失
data-* 属性不能写在 里,全局上下文要挂到 html>
想把环境、AB 分组、用户 ID 等字段塞进埋点 payload?千万别往 里加 data-env 或 data-user-id。HTML 规范禁止,浏览器直接忽略,JS 读不到。
正确做法:
- 把所有全局上下文属性写在
标签上,例如: - JS 里统一用
document.documentElement.dataset.env读取,无需等待 DOM 加载 - 避免挂到
:SPA 框架可能整个替换body,导致 data 属性丢失
上报必须用 navigator.sendBeacon,fetch 不可靠
用户点击「立即购买」后跳转下单页,或关闭标签页前触发 LCP 上报——这时用 fetch 或 XMLHttpRequest,90% 请求会被浏览器终止,数据永久丢失。
关键细节:
-
navigator.sendBeacon()是唯一能保证页面卸载前发出请求的机制,且不阻塞主线程 - payload 必须是
ArrayBuffer、Blob或FormData,不能直接传 JSON 对象;常见写法:new Blob([JSON.stringify(payload)], {type: 'application/json'}) - URL 必须是同源或配置了 CORS 的 endpoint,否则 beacon 会静默失败(无 error 抛出)
- 别依赖返回值判断成功:beacon 只保证“尽力发送”,服务端需做好幂等和重试
移动端 click 事件不可靠,首屏曝光要用 IntersectionObserver
首屏元素是否真正进入视口,不能靠 click 或 scroll 估算。iOS/Android WebView 对 click 有 300ms 延迟,且滚动惯性会让元素快速进出可视区,手动计算坐标极易误判。
正确姿势:
- 对首屏关键节点(如 banner、商品主图)加
data-track="exposure",再用IntersectionObserver监听其isIntersecting === true且intersectionRatio > 0.5 - 避免监听
window的scroll:性能差、触发频繁、移动端 scroll 事件节流严重 - 曝光上报需带唯一标识:
el.dataset.eventId,否则同个组件复用时无法区分不同实例
首屏指标采集最易被忽略的点:指标本身是异步触发的,但它的上下文(如页面路径、用户身份)必须在采集那一刻就确定。如果等 PerformanceObserver 回调里再去读 location.href 或 document.title,可能已被 SPA 路由修改——得在 observer 初始化时就快照一份。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











