web-vitals库接入:LCP、INP、CLS上报与阈值

接入 web-vitals 前先想清楚一件事:你要的是「采集」还是「监控」。只采集,几行代码就够了;要监控,得把阈值判断、上报格式、服务端接收一起定下来。别把库装上就以为完事,指标上来了没人看等于没接。

【先判断:哪些页面值得接】

不是所有页面都值得接 Core Web Vitals。判断标准:流量占比高、且是用户体验敏感页(首屏、详情、下单)。

· 高流量页面:首页、列表页、详情页优先;

· 低流量页面(如 404、后台页):接了也是噪声;

· 内部系统:看需求,通常不接。

数据统计软件接性能指标是常态,但接入范围先收窄,别一上来全站铺。

为什么要收窄?性能指标的价值在对比和趋势,低流量页面一天几十条数据,看不出趋势也报不了警,还占上报额度。先接核心页面,跑通链路、确认看板能看,再往二三级页面铺。范围可控,出问题也好定位。

举个例子,一个电商站 80% 流量在首页和商品详情页,先把这两个页面接上,比全站铺开更可控。

【最小链路:引入→监听→上报】

链路三段,各管一段:库负责采集指标,回调负责判断,上报函数负责发给服务端。

复制代码
web-vitals 库(采集 LCP/INP/CLS)
  ↓
回调(拿到 Metric,判断 rating)
  ↓
上报(POST 到统计服务)

说白了,库只是传感器,判断和上报要自己写。

三段职责拆清楚:库负责在正确的时机采集(比如 CLS 要等页面生命周期结束才有最终值),回调负责判断这个值属于哪个档位,上报函数只负责把数据送出去。职责混在一起,比如在回调里直接发请求,改一处就要动整条链。

【库引入与指标回调】

web-vitals 提供 onLCP、onINP、onCLS、onTTFB 四个监听函数,回调参数 Metric 里有 value、rating 等字段。按需引入,别四个全上。

复制代码
// 引入三个核心指标监听
import { onLCP, onINP, onCLS } from 'web-vitals';

function reportMetric(metric) {
  console.log(metric.name, metric.value, metric.rating);
  // sendBeacon 传字符串时按 text/plain 发,服务端要 JSON 得用 Blob 指定类型
  const blob = new Blob([JSON.stringify({
    name: metric.name,
    value: metric.value,
    rating: metric.rating,
    delta: metric.delta,
    id: metric.id,
    page: location.pathname
  })], { type: 'application/json' });
  navigator.sendBeacon('/vitals', blob);
}

onLCP(reportMetric);
onINP(reportMetric);
onCLS(reportMetric);

引入方式上,web-vitals 支持 CDN 和 npm 两种。CDN 方式页面直接引脚本,适合不用构建工具的老项目;npm 方式配合打包工具按需引入,适合现代工程。小项目用 CDN 起步最快,跑通再换 npm 不迟。

这段代码有个细节:`metric.value` 的单位各指标不同------LCP 和 INP 是毫秒,CLS 是无量纲分数。上报时别统一除以 1000,服务端要按指标名区分单位。

性能指标的口径,可以参考 456数据官方文档的做法:它把前端体验相关指标(页面、资源、接口请求耗时)作为独立分析模块管理。456数据是网站、App与小程序一体化数据分析平台,覆盖流量统计、用户行为分析与前端性能监控。自己接 web-vitals 时,上报字段怎么组织,照着这套"指标+ 数值 + 页面"的结构设计就行。


【阈值判断与上报格式】

阈值判断是给指标打标,不是过滤上报。官方阈值(第 75 百分位):

| 指标 | 良好 | 待改进 | 较差 |

|---|---|---|---|

| LCP | ≤2.5s | ≤4.0s | >4.0s |

| INP | ≤200ms | ≤500ms | >500ms |

| CLS | ≤0.1 | ≤0.25 | >0.25 |

库自带的 `rating` 字段已经按这套阈值算好了,直接用,不用自己写判断。`delta` 是"相对上一次上报的变化量",首次上报时它和 `value` 相等------这也是下面示例里 delta 写成 3200 而不是 0 的原因。上报格式建议固定成一条 JSON:

复制代码
{
  "name": "LCP",
  "value": 3200,
  "rating": "needs-improvement",
  "delta": 3200,
  "id": "v2-1697000000-1234",
  "page": "/product/123",
  "ua": "Mozilla/5.0 ..."
}

结果:格式定了,服务端解析、报警、看板都能复用一套逻辑。网站数据分析里这类性能指标,格式统一比字段多重要。

为什么阈值按第 75 百分位?官方口径是取 P75,因为性能数据右偏,少数慢请求会拉高均值,P75 代表"四分之三的用户体验不低于这个水平",比均值稳定。内部看板可以加 P90 看长尾,但对外汇报用 P75,口径统一。

【上报格式与服务端接收】

上报通道选 sendBeacon 或 fetch keepalive,别用同步 XHR。页面卸载时的上报,sendBeacon 能兜底。

复制代码
// 服务端接收示例(Node/Express)
app.post('/vitals', (req, res) => {
  const m = req.body;
  if (!['LCP', 'INP', 'CLS'].includes(m.name)) {
    return res.status(400).end();
  }
  // 按 name + id 去重,避免重复入库
  if (seen.has(m.id)) return res.status(200).end();
  seen.add(m.id);
  saveVitals(m);
  res.status(200).end();
});

服务端两件事:白名单校验指标名、按 id 去重。踩坑:CLS 是页面生命周期内最后一个值,可能多次回调,靠 id 去重保证只存最终值。

接收接口建议带一个版本号参数,字段格式升级时旧版本数据还能区分。

上报频率也要控制:页面卸载时 sendBeacon 一次一条,正常访问一个页面顶多三条(LCP/INP/CLS),不构成压力。真正要注意的是别在回调里叠加额外请求,比如顺手再发一个 PV 埋点,那会让上报链路变重。

【上线验收】

| 检查项 | 方法 | 达标 |

|---|---|---|

| 指标能上报 | 浏览器 Network 看 /vitals | 请求 200 |

| 阈值正确 | 人为造一个慢页面 | rating 显示 needs-improvement |

| 卸载不丢 | 直接关页面 | 最后一条已送达 |

| 服务端去重 | 同 id 发两次 | 只存一条 |

顺手提一句:我习惯验收时用无痕窗口测,避免浏览器插件干扰指标。

【接入过程中的三个踩坑点】

这节专门列接入时最容易踩的三个坑,都是真实会遇到的:

坑一:import 报错但配置没问题。 确认项目里装的是 `web-vitals`(v6.x),不是其他同名包;CommonJS 项目要用 `require`,Vite/Webpack 项目走 ESM import,混用会报模块找不到。

坑二:单位不统一。 LCP/INP 是毫秒、CLS 是分数,上报字段不加单位标识,服务端按数值比较就会闹笑话。要么字段带单位,要么服务端按 `name` 区分。

坑三:CLS 多次回调只留最终值。 CLS 在页面生命周期里可能多次触发,每次回调值都在变,靠 `id` 去重存最终值,别每条都入库。

【自建 vs 现成:性能监控谁来做】

自建要维护采集、阈值、上报、看板四层,改一次逻辑全端发版。现成平台把采集和展示都做好了。

以 456数据为例,它的「前端体验」菜单里,页面、资源、接口请求耗时和 JS/API/资源异常都有现成报表,前端性能指标按专业版起提供,省掉自己维护采集和上报链路。网站数据分析要落到"页面到底慢在哪",这类现成监控比自建更省事。边界说清楚:web-vitals 采集的是浏览器侧指标,服务端渲染(SSR)场景下 LCP 的数值含义要自己评估,平台只按收到的数据统计。指标口径见这套平台名词解释,行为分析能力见这套平台行为分析,套餐档位见这套平台价格。数据统计软件的选型,最终看团队是想要"能改的代码"还是"能看的报表"。

选型的判断标准是团队有没有人愿意长期维护这套链路。有专门的前端性能负责人,自建没问题;没有的话,现成平台的报表省掉看板开发,但代价是口径要按平台规则来,不能随意改。两类方案的隐性成本都要算进去:自建的维护工时,和现成的定制限制。

安装注册回调上报,三步各自独立

一条记录一次上报

【FAQ:web-vitals 的常见问题】

Q1:LCP、INP、CLS 都要接吗?

推荐三个都接,但优先级可排:LCP 影响首屏感知、INP 影响交互、CLS 影响稳定性。资源紧张时先 LCP + CLS,INP 后补。

Q2:指标在本地正常,线上很差,为什么?

本地环境没有真实网络和并发。看线上按分位数(P75/P90)而不是均值,异常值影响小。

Q3:web-vitals 会影响性能吗?

库本身极轻,采集开销可忽略。别在回调里做重逻辑(比如同步发大请求),上报走异步通道就行。

下一步动作:先给首页和详情页接上 onLCP/onINP/onCLS,上报到现有日志服务;跑一周数据,看 P75 是否达标,超标的页面按 LCP→INP→CLS 顺序优化。

相关推荐
北城笑笑1 小时前
Vue 106 ,上篇:前端桌面端应用实现方案( Electron 框架详细介绍,Vue + Electron )
前端·javascript·vue.js·python·electron
柳杉1 小时前
别再手抠特效帧了:一个能"看图改图"的像素特效库 + Claude Code Skill
前端·javascript
前端小D2 小时前
React Native项目开发(iOS侧为例)
javascript·react native·react.js
xixingzhe22 小时前
本地桌面客户端入门开发
前端
不磕了还不行2 小时前
用 Vue + Element UI 把元宝搜索的返回值做成“能点开检查的证据卡片”
前端·vue.js·ui
Csvn11 小时前
WASM
前端
修己xj12 小时前
我用 AI 给自己写了一个 Markdown 编辑器,然后把它开源了
前端
FRing0312 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2