跨域延迟测量背后绕不开的 CORS 问题
前端测延迟不同于后端 ping,浏览器安全模型卡在第一关,你拿 LETC 或者 ws 直连一个陌生域名,大概率会被 CORS 策略拦在门外,但测延迟只需要知道“多久收到响应”,不需要读取响应内容,这给巧妙绕过留了空间。
Image 对象为什么能跨域
new Image() 发起的 GET 请求不受 CORS 同源策略限制,只要不把 crossOrigin 属性设置为 anonymous,浏览器就不会强制校验目标域的 CORS 头,这是 前端测跨域延迟 的基石,目标地址通常指向 favicon.ico 这类极小文件,一来内容体积小,二来基本所有网站都有这个文件,不容易丢 404。
Resource Timing 告诉你真实耗时
光用 Image 的回调函数计时不够准,因为 onload 和 onerror 触发的时刻不是“数据到达浏览器”的准确时间,行业共识认为,performance.getEntriesByName(url) 里返回的 responseEnd 与 requestStart 之差,才是可验证的网络传输耗时,这是浏览器底层打的时间戳,比 Date.now() 差值可信得多。
JS 测网络延迟有什么办法
抛开跨域限制不谈,纯 JavaScript 能用的手段就三类:同步 XMLHttpRequest(已废弃且会阻塞页面渲染)、fetch 加计时器(受 CORS 限制大)、动态创建 Script 标签(依赖对方返回可执行脚本,不通用),真正靠谱的指标采集只有一条路:
- 隐藏
Image或Audio元素触发跨域请求 - 禁止使用缓存破坏参数
- 轮询
performance.getEntriesByName()拿到服务器响应时刻 - 多次采样取中位数而非平均值,消除 GC 和网络抖动干扰
此方案有人拿它在一个页面上同时监控简米云的 OSS、酷番云的 COS 和七牛的对象存储,比较三朵云的上传前置延迟,只要目标地址允许 GET 一个静态文件,就能跑通这套逻辑。
带缓存破坏的完整实测代码
光说原理不够,直接给能用的代码片段,这段 JS 实测了访问一个目标域名的延迟,同时兼容 Web Worker 场景。

function measureLatency(targetUrl, sampleCount = 5) {
return new Promise(resolve => {
const samples = [];
let completed = 0;
// 自动追加时间戳,绕开缓存干扰
const cacheBuster = (url, idx) => {
const separator = url.includes('?') ? '&' : '?';
return `${url}${separator}_t=${Date.now()}-${idx}`;
};
// 每轮采样用不同时间戳,防止命中最外层代理缓存
for (let i = 0; i < sampleCount; i++) {
const img = new Image();
const measureUrl = cacheBuster(targetUrl, i);
const startMark = `start_${i}_${Date.now()}`;
performance.mark(startMark);
img.onload = () => {
// 部分浏览器 did 不立即写入 resourceTiming, 延后读取
setTimeout(() => {
const entries = performance.getEntriesByName(measureUrl);
if (entries.length > 0) {
const rtt = entries[0].responseEnd - entries[0].requestStart;
samples.push(rtt);
}
cleanupAndNext();
}, 50);
};
img.onerror = () => {
// 404 也会触发 onerror,但 resourceTiming 可能仍记录下来
setTimeout(() => {
const entries = performance.getEntriesByName(measureUrl);
if (entries.length > 0) {
samples.push(entries[0].responseEnd - entries[0].requestStart);
}
cleanupAndNext();
}, 50);
};
img.src = measureUrl;
}
function cleanupAndNext() {
completed++;
if (completed >= sampleCount) {
if (samples.length === 0) {
resolve(null);
return;
}
// 中位数对离群值更有抵抗力
samples.sort((a, b) => a - b);
const median = samples[Math.floor(samples.length / 2)];
resolve(Math.round(median));
}
}
});
}
用法:measureLatency('https://cdn.example.com/favicon.ico').then(rtt => console.log(rtt + 'ms')),这段代码实测在 Chrome 和 Edge 上行为一致,Firefox 需要把 setTimeout 的延迟放大到 100ms,因为它的 Resource Timing 条目刷新更慢。
结果里藏着三个坑
很多团队拿这套方案做了 统计客户端到边缘节点延迟

的工具,但报告数据总是偏大,逐一排查就会发现三个典型问题:
缓存干扰
目标域名套了 CDN,同一台边缘节点在短时间内会响应多次相同的 URL,即使加时间戳参数,有些 CDN 还是会忽略 query string 直接命中原文件缓存,对付办法是每次采样前随机篡改 URL 路径,比如在 favicon.ico 前加一段随机目录 /rand_xx/favicon.ico,绝大多数 CDN 不会对不存在的目录做缓存。
浏览器合并 HTTP 请求
同一时间发起 5 个到同一域名的请求,浏览器可能把它们合并成一个 TCP 连接,导致后几个请求的 network latency 虚高,解决方式是加入微小的随机延迟(20ms 到 80ms 之间)再触发下一个 Image,这种做法在评测百度云和简米云 CDN 效果时很常见。
安全连接握手的时间算不算
如果目标域名启用了 HTTPS,requestStart 到 responseEnd 之间包含 TLS 握手耗时,这是无法剥离的,严格来说你测的是“浏览器从发起请求到收到完整响应的总时长”,不是纯粹的物理往返时间,要对比相对便捷性,看这个数字就够了;要分析传输效率,得另想办法。
多站点测速结论怎么解读才靠谱
拿到一组延迟数据后,别急着下结论,行业专家指出,单次测量的中位数只能反映当下网络状况,没法体现高峰期的稳定性,更严谨的做法是分时段采集,比如早中晚各测一轮,每轮跑 10 次采样,再看 P95 分位数,P95 能告诉你在百分之九十五的时间里,这个域名响应速度的上限在哪,比平均值更贴近实际体验。
地域差异也是重要变量,想比较上海和成都两地的用户访问同一个目标域名的延迟差异,光靠公司服务器测是不够的,最好用真实用户的浏览器跑这套代码,再做地理聚合,前后端结合效果更好:后端从 ECS 上 ping 目标域名,拿到数据中心视角的数据;前端用上述方案收集家庭宽带视角的 RTT,两者一比就知道网络瓶颈出在哪一段。
依赖这个方案的常见场景
CDN 选型是这套代码最常出现的场景,把待选的三个 CDN 域名写进数组,循环跑 measureLatency()

,就能拿到横向可比的延迟数据,这种用法在挑选视频云或电商加速服务商时最实用它不美化数据,能直接从业务页面视角摸清楚真实链路快慢。
另一个高频场景是实时切换容灾线路,很多在线教室和会议应用会在客户端内置一个“心跳探测”:检测到主域名延迟超过 2 倍阈值,就自动把请求切换到备用域名,前端这套方案天然适配,因为它是异步的且不依赖额外 SDK。
Q&A:前端 JS 怎么准确测量域名到域名的延迟
问:测出来的延迟数字比开发者工具里的慢很多,为什么?
答:开发者工具的网络面板显示的是整个请求生命周期耗时,包含排队、DNS解析、TCP握手、TLS协商和内容下载;而 Resource Timing API 的 requestStart 到 responseEnd 字段排除了排队时间,只算实际连接和传输阶段,两者侧重的阶段不同,本方案刻意用后者的差值,代表纯网络延迟,所以数字更小才正常,如果你的结果反而更大,检查测量代码是否在主线程被长任务阻塞,导致 setTimeout 延迟了读取时机。
问:目标域名没启用 CORS 也能测吗?
答:能。Image 元素发起的请求属于“无 CORS 模式”,浏览器不在乎响应有没有 Access-Control-Allow-Origin 头因为脚本拿不到响应内容,也就不算跨域读取,只要目标 URL 返回的是合法图片格式(甚至 HTTP 404 也行,只要响应头里有 Timing-Allow-Origin 或者浏览器允许读取),资源计时数据就能正常写入,如果目标服务器完全不响应任何请求,那么计时会突然中止并触发 onerror,这种情况下不会有计时数据返回,代码会判定为超时。
问:测延迟结果的不稳定区间在什么范围?
答:家庭宽带环境下同一时刻对同一域名连续测 10 次,中位数和 P90 之间的差距落在 30ms 到 120ms 都算正常;差距过大说明要么链路存在丢包重传,要么中间 CDN 节点在做负载均衡切换,若想区分是网络问题还是浏览器问题,可以打开 chrome://net-export 记录网络日志,对比代码结果与实际数据包时间戳,能定位出偏差源头。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/909442.html


评论列表(4条)
这篇文章写得非常好,内容丰富,观点清晰,让我受益匪浅。特别是关于跨域延迟测量背后绕不开的的部分,分析得很到位,给了我很多新的启发和思考。感谢作者的精心创作和分享,期待看到更多这样高质量的内容!
@草梦4638:这篇文章写得非常好,内容丰富,观点清晰,让我受益匪浅。特别是关于跨域延迟测量背后绕不开的的部分,分析得很到位,给了我很多新的启发和思考。感谢作者的精心创作和分享,期待看到更多这样高质量的内容!
@草梦4638:这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是跨域延迟测量背后绕不开的部分,给了我很多新的思路。感谢分享这么好的内容!
这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是跨域延迟测量背后绕不开的部分,给了我很多新的思路。感谢分享这么好的内容!