直接读 performance.timing 会报 NaN 或 0,因其在 Safari、iOS QQ 浏览器及多数 WebView 中基本不填充字段,Chrome 120+ 已弃用,应优先使用 performance.getEntriesByType('navigation')[0]。

为什么直接读 performance.timing 会报 NaN 或 0?
因为 performance.timing 在 Safari、iOS QQ 浏览器、多数 WebView 中基本不填充字段,navigationStart 常返回 0 或 undefined,一减就出 NaN。Chrome 120+ 已彻底弃用它,Firefox 和 Safari 仅保留兼容性壳子。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 永远优先取
performance.getEntriesByType('navigation'),只取[0]即可,它返回标准的PerformanceNavigationTiming实例 - 若数组为空,说明调用太早——必须等
document.readyState === 'complete'或监听window.addEventListener('load', ...) - 降级逻辑只在极老环境(如 IE11)才需要:
performance.navigationStart || (performance.timing && performance.timing.navigationStart) || Date.now()
domContentLoadedEventEnd 是不是 DOM 加载完成时间?
是,但它不是“用户可交互”的可靠指标。这个时间点只代表 HTML 解析完毕、同步脚本执行完,但可能仍被 defer 脚本、Web Font、图片解码阻塞。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 上报时别只用单一时点,应组合计算:
domContentLoadedEventEnd - fetchStart(DOM 解析耗时),domInteractive - domLoading(纯 HTML 解析阶段) - 注意
domContentLoadedEventEnd在 SPA 路由切换后不会更新,需配合PerformanceObserver监听新导航 - 如果页面含大量
async脚本或img,这个值可能远早于真实可操作时间,建议额外打点performance.mark('dom-ready')并在DOMContentLoaded回调里触发
如何避免上报数据全是 0 或缺失资源条目?
performance.getEntriesByType('resource') 返回空或字段为 0,90% 是时机或跨域配置问题,不是 API 失效。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 必须在
window.load后调用,否则动态插入的资源(如懒加载图片)还没进队列 - 跨域资源(CDN 图片、外部 JS)需服务端响应头带
Timing-Allow-Origin: *,否则duration、responseStart全为 0 - 前端请求必须显式加
crossorigin属性:<script src="a.js" crossorigin>,否则浏览器不收集完整 Timing - 缓冲区默认只有 150 条,大页面易丢数据,提前调用
performance.setResourceTimingBufferSize(500)
上报 DOM 加载时间时最容易忽略的边界情况
不是所有导航都走标准流程。用户从缓存回退、PWA 离线加载、Service Worker 拦截响应,都会让关键字段失效。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 检查
nav.type:若为'back_forward',responseStart常为 0,此时 TTFB 不可算,应跳过或标记为 “cached” - SPA 场景下,
getEntriesByType('navigation')只记录首次加载,后续路由变化需用performance.mark()+performance.measure()手动打点 - 不要在
window.onload里才开始收集 —— 此时首屏已渲染完毕,TTFB、FP、FCP 都错过了,应在<head>就注入标记逻辑
真正要上报的不是“某个时间点”,而是“用户感知到 DOM 就绪的上下文”:是否缓存、是否 SSR、是否有 blocking script —— 这些都得和时间值一起带上,否则光看毫秒数毫无意义。



















