performance.getentriesbytype("resource") 返回已完成加载的资源performanceresourcetiming对象数组,但需满足资源加载完成、非强缓存且跨域资源服务端配置了timing-allow-origin: *,否则多数网络阶段字段为0或nan。

performance.getEntriesByType("resource") 能拿到外部资源(CDN、第三方脚本、字体、图片等)各阶段的毫秒级耗时,但前提是资源已完成加载,且服务端配了 Timing-Allow-Origin: * —— 缺一不可,否则多数字段为 0 或 NaN。
为什么直接调用 performance.getEntriesByType("resource") 经常返回空数组或字段全为 0
常见错误现象:页面刚打开就执行该调用,结果为空;或看到大量 domainLookupStart、connectStart 等字段是 0。
- 资源未完成加载:该 API 只返回 已结束加载 的资源,动态插入的
<script></script>或fetch()若还没 resolve,不会出现在列表里 - 缓存干扰:强缓存(
from cache)下,浏览器跳过网络阶段,只保留startTime、responseStart、responseEnd和duration,其余字段清零 - 跨域缺失头:外部资源(如
https://cdn.example.com/xxx.js)若服务端没返回Timing-Allow-Origin: *,所有网络阶段字段(DNS、TCP、SSL、TTFB)都会被置零,只留基础时间 - 执行时机太早:应在
window.addEventListener("load", ...)后调用,或用PerformanceObserver监听"resource"类型条目
如何正确提取 DNS、TCP、TTFB、下载等关键阶段耗时
重点不是套公式,而是先判断字段是否有效 —— 检查是否大于 0,再做减法。跨域资源即使有值,也要确认来源是否可信。
-
domainLookupEnd - domainLookupStart:仅当两者都 >0才可信;若等于0,说明走的是本地 hosts 或 DNS 缓存,或跨域无权限 -
connectEnd - connectStart:包含 TCP 握手 + TLS 协商;若secureConnectionStart > 0,可用connectEnd - secureConnectionStart单独看 SSL 耗时 -
responseStart - requestStart就是 TTFB,但注意:如果requestStart === 0,这个差值无效 —— 此时应退回到responseStart - startTime作近似 -
responseEnd - responseStart是纯下载耗时,对大文件(如视频、字体)最有意义;但若资源极小(
过滤 CDN 或第三方资源并计算平均 TTFB 的实操写法
不要依赖 initiatorType 做唯一判断 —— 第三方 SDK 动态插入的 script 可能被归为 "other",而 fetch 请求在非顶层上下文发起时会显示为 "xmlhttprequest"。
- 优先用
name字符串匹配域名:resources.filter(r => r.name.startsWith("https://cdn.jsdelivr.net")) - 排除缓存资源(避免污染统计):
r.transferSize > 0表示确实走了网络;r.encodedBodySize > 0更稳妥,因有些 CDN 会压缩后返回transferSize === 0但仍有内容 - 安全计算 TTFB:
const ttbfs = resources .filter(r => r.name.includes("cloudflare.com") && r.responseStart > 0 && r.requestStart > 0) .map(r => r.responseStart - r.requestStart); const avgTtfb = ttbfs.length ? Math.round(ttbfs.reduce((a, b) => a + b, 0) / ttbfs.length) : NaN;
真正难的不是取数,而是分辨哪些数字能信、哪些是浏览器填的占位符。尤其在分析 CDN 或广告资源时,Timing-Allow-Origin 配不配、配没配对,直接决定你看到的是真相还是幻觉。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











