<p>应使用 performance.getEntriesByType("navigation")[0] 获取 PerformanceNavigationTiming 实例,读取 domInteractive、domContentLoadedEventStart/End 等字段;DOM 解析耗时用 domInteractive - fetchStart,构建+同步脚本耗时用 domContentLoadedEventEnd - responseEnd(responseEnd 为 0 时兜底 fetchStart);SPA 需手动打点或 MutationObserver 监控;白屏时间须用 PerformanceObserver 监听 'paint',不可与 domInteractive 混淆。</p>

怎么安全拿到 DOM 构建阶段的起止时间
不能直接用 performance.timing.domInteractive 或 performance.timing.domContentLoaded —— 这些字段在 Safari、iOS WebView、部分安卓 WebView 中常为 0 或 undefined,且 performance.timing 已被 W3C 正式废弃。
正确做法是通过 performance.getEntriesByType("navigation")[0] 获取 PerformanceNavigationTiming 实例,再读取其语义清晰的字段:
-
domInteractive:HTML 解析完成、DOM 树构建完毕的时间戳(单位毫秒,高精度) -
domContentLoadedEventStart:DOMContentLoaded 事件开始触发的时间(含同步脚本执行) -
domContentLoadedEventEnd:DOMContentLoaded 事件回调全部执行完的时间
注意:这些字段只在当前页主文档导航中有效;iframe 或 SPA 路由切换产生的条目需过滤,校验 entry.name === location.href 和 entry.initiatorType === "navigation"。
DOM 解析耗时怎么算才不踩坑
常见错误是直接用 domInteractive - domLoading,但 domLoading 在 Level 2 规范中已被移除,现代接口里它不存在 —— 所以这个差值根本拿不到。
立即学习“前端免费学习笔记(深入)”;
实际应使用:
- HTML 解析耗时 ≈
domInteractive - fetchStart(反映从请求发起后到 DOM 树就绪的总延迟) - DOM 构建 + 同步脚本执行耗时 ≈
domContentLoadedEventEnd - responseEnd(更贴近用户可交互前的真实阻塞) - 若
responseEnd为 0(如缓存加载或type === "back_forward"),改用domContentLoadedEventEnd - fetchStart作兜底
特别提醒:domInteractive 为 0 并不等于解析快,而是可能被浏览器跳过(如空 HTML 或服务端直出异常),务必结合 entry.type 和资源加载状态交叉判断。
为什么 SPA 页面里 DOM 时间经常不准
单页应用中,performance.getEntriesByType("navigation") 返回的往往是首次完整加载的记录,后续路由跳转不会触发新 navigation 条目 —— 所以你读到的 domInteractive 等值,仍是初始页的,和当前视图完全无关。
应对方式只有两个:
- 在每次路由变更后,手动打点:
performance.mark("route-enter"),配合performance.measure()记录 DOM 更新区间(注意 iOS Safari 对measure()支持不稳定,建议 fallback 到Date.now()) - 监听
document变化(如MutationObserver监控body子节点增删),在关键节点插入标记,避免依赖 navigation API
别指望靠一次 getEntriesByType("navigation")[0] 覆盖整个 SPA 生命周期 —— 它只忠于“页面级导航”,不是“视图级更新”。
白屏时间与 DOM 就绪时间容易混淆的点
白屏时间(Time to First Paint)和 DOM 就绪时间(domInteractive)常被混为一谈,但它们物理意义完全不同:
- 白屏时间 =
first-paint时间戳 −fetchStart,必须用PerformanceObserver监听'paint'类型获取,不能靠 navigation 条目推算 -
domInteractive是 DOM 树构建完成的信号,但它不保证样式已就绪、JS 已执行、首屏元素已渲染 —— 用户可能仍看到空白或布局错乱 - 真正影响“可感知交互”的,是
domContentLoadedEventEnd(同步逻辑执行完)或loadEventEnd(所有资源加载完),而非domInteractive
线上监控如果只报 domInteractive,等于只测了半程 —— 它背后藏着大量未执行的初始化脚本、CSSOM 构建、布局计算,这些才是卡顿主因。



















