✅一、交给 web‑vitals不要自己手写 PerformanceObserver库内部已经封装好PerformanceObserver处理了 buffered、SPA 软导航、BFCache、多次候选值、浏览器兼容性RUM 采集直接用GitHubLCP 最大内容绘制INP 交互到下一次绘制新版核心指标替代 FIDCLS 累积布局偏移FCP 首次内容绘制TTFB 首字节时间import {onLCP,onINP,onCLS,onFCP,onTTFB} from web‑vitals onLCP(上报函数) onINP(上报函数) onCLS(上报函数) onFCP(上报函数) onTTFB(上报函数)底层依然是 Performance API只是复杂规则由谷歌维护业务埋点不要重复造轮子。✅二、必须自己手写原生 Performance APIweb‑vitals 不提供1导航耗时 navigationDNS、TCP、TLS、DOMContentLoaded、load 完整时间线performance.getEntriesByType(navigation)window.addEventListener(load, () { const navEntries performance.getEntriesByType(navigation); const nav navEntries[0]; console.log(DNS耗时, nav.domainLookupEnd - nav.domainLookupStart); console.log(TCP握手, nav.connectEnd - nav.connectStart); console.log(DOMContentLoaded, nav.domContentLoadedEventEnd); console.log(load完成, nav.loadEventEnd); })2资源加载 timingjs/css/img/font各个静态资源下载、解析耗时PerformanceObserver typeresourceconst resObserver new PerformanceObserver((list) { list.getEntries().forEach(entry { console.log(资源地址, entry.name); console.log(下载耗时, entry.responseEnd - entry.startTime); }) }) resObserver.observe({type:resource,buffered:true})3长任务 LongTask / LoAF 长动画帧主线程阻塞定位卡顿根源分析 TBT 总阻塞时长PerformanceObserver typelongtaskconst longTaskObserver new PerformanceObserver((list) { list.getEntries().forEach(entry { console.log(长任务阻塞时长(ms), entry.duration); }) }) longTaskObserver.observe({type:longtask,buffered:true})4自定义打点SPA 路由、接口、组件挂载、自定义首屏performance.mark()/performance.measure()比如 Vue/React 路由切换耗时、接口耗时、自定义首屏完成时间web‑vitals 管不了业务自定义节点。//开始打点 performance.mark(route-start) setTimeout((){ //结束打点计算间隔 performance.mark(route-end) performance.measure(route-cost,route-start,route-end) const measureList performance.getEntriesByName(route-cost) console.log(路由耗时ms,measureList[0].duration) //清理避免内存堆积 performance.clearMarks(); performance.clearMeasures(); },800)5TTI、TBT浏览器没有直接原生条目web‑vitals 也不输出 需要收集长任务、网络空闲窗口自己算法算出实验室指标线上 RUM 很少采集。6ElementTiming 自定义元素计时指定某个 DOM广告、模块渲染耗时html 增加elementtiming属性div elementtimingad-block广告模块/divJS 采集const eleObserver new PerformanceObserver(list{ list.getEntries().forEach(e{ console.log(指定DOM渲染完成时间,e.renderTime) }) }) eleObserver.observe({type:element,buffered:true})✅三、一句话选型口诀用户体验核心 5 大指标LCP/INP/CLS/FCP/TTFB→ web‑vitals资源、长任务、导航细节、业务自定义打点、SPA 路由耗时 → 原生 PerformanceObserver /markmeasureTTI/TBT 属于实验室指标线上一般不采集✅四、面试补充坑点web‑vitals 只能拿到标准体验指标不能定位阻塞的 JS 文件、图片资源排查问题依然要原生资源 / 长任务监控web‑vitals 不支持自定义 DOM 计时业务首屏、路由切换埋点必须自己 mark不要自己手写 LCP/CLS/INP 采集实现规则复杂容易不准线上 RUM 优先库。