应使用performance.getEntriesByType('navigation')替代已废弃且兼容性差的performance.timing,因其返回PerformanceNavigationTiming实例,字段语义清晰、精度高、现代浏览器全面支持,并能准确计算TTFB、DOM解析、资源加载等首屏关键阶段耗时。

别用 performance.timing,它在 Safari 和多数 WebView 里基本失效,且已被标准废弃;直接上 performance.getEntriesByType('navigation') 拿 PerformanceNavigationTiming 实例,才是稳定、语义清晰、字段可用的正解。
为什么 performance.timing 不能信
常见错误现象:performance.timing.navigationStart 返回 0 或 undefined,导致算出负数或 NaN;domainLookupStart、connectStart 等字段全为 0,但实际 DNS/TCP 并没跳过——只是 Safari(含 iOS QQ 浏览器)、旧版 WebView 根本不填这些值。
兼容性事实:performance.timing 在 IE9+、Chrome11+、Firefox7+ 可用,但 Safari 始终未完整实现,且 W3C 已标记为 deprecated。
替代方案必须 fallback 到现代接口:
立即学习“前端免费学习笔记(深入)”;
-
performance.navigationStart(注意不是timing.navigationStart)是首选,规范定义、所有现代浏览器支持 - 降级到
performance.timing && performance.timing.navigationStart仅用于极老 Chrome/Firefox(2013 年前) - 最后 fallback 到
Date.now(),适用于页面刚打开 JS 就执行的极端场景
怎么从 navigation 条目拆解首屏关键阶段
performance.getEntriesByType('navigation') 返回数组,取 [0] 即可拿到本次导航的完整时序。每个字段都是微秒级精度,直接相减即得各阶段耗时。
重点看这几个差值:
-
nav.responseStart - nav.requestStart:TTFB,超过 800ms 要查后端或 CDN -
nav.domContentLoadedEventEnd - nav.responseEnd:DOM 解析 + 同步 JS 执行耗时,> 300ms 检查是否含未拆分的大型 inline 脚本 -
nav.loadEventEnd - nav.domContentLoadedEventEnd:异步资源拖尾时间,高说明图片、iframe、字体加载慢,需结合resource条目交叉验证 -
nav.domInteractive - nav.domLoading:HTML 解析耗时,若异常高,可能是 HTML 体积过大或含阻塞解析的同步脚本
注意:nav.type === 'back_forward' 时,responseStart 可能为 0,此时 TTFB 计算应跳过。
如何安全获取资源各阶段耗时(DNS/TCP/SSL/TTFB/下载)
performance.getEntriesByType('resource') 返回已完成加载的资源列表,但字段是否有效取决于三件事:资源已加载完成、未走强缓存、跨域资源服务端返回了 Timing-Allow-Origin: * 头。
计算前务必先校验字段有效性:
-
entry.domainLookupStart > 0 && entry.domainLookupEnd > 0→ 才可信 DNS 时间:entry.domainLookupEnd - entry.domainLookupStart -
entry.connectStart > 0 && entry.connectEnd > 0→ TCP+TLS 时间:entry.connectEnd - entry.connectStart;若entry.secureConnectionStart > 0,可用entry.connectEnd - entry.secureConnectionStart单独看 SSL 耗时 -
entry.requestStart > 0 && entry.responseStart > 0→ TTFB:entry.responseStart - entry.requestStart;若requestStart === 0,退回到entry.responseStart - entry.startTime近似 -
entry.responseEnd - entry.responseStart是纯下载耗时,对字体(.woff2)、大图、视频最有意义
过滤 CDN 或第三方资源别依赖 initiatorType,用 entry.name.startsWith('https://cdn.example.com') 更可靠。
为什么不能等 window.onload 再开始测
window.onload 触发时,图片、字体、异步脚本、iframe 已加载完毕,此时读 performance 数据虽然“完整”,但已经错过真实瓶颈点——比如 TTFB 高、JS 执行阻塞渲染、布局抖动等,全被掩盖了。
真正要监控的,是用户感知的关键路径:
- 首字节(TTFB)发生在
responseStart,此时 DOM 还没开始解析 - 首屏内容(FCP)靠
PerformanceObserver监听'first-contentful-paint'类型,不能靠手动计算 - 长任务(>50ms)会卡顿主线程,只能靠
PerformanceObserver捕获'longtask',轮询getEntriesByType会漏掉
最易被忽略的是:很多性能问题根本不出现在控制台报错里,也不影响功能,只表现为“偶尔卡一下”——这种必须靠 PerformanceObserver 主动监听,而不是等页面“加载完”再翻日志。


















