navigator.connection.rtt 可映射为三档并发阈值:≤50ms用6~8,50ms<rtt≤150ms用3~4,>150ms用1~2;需兜底effectiveType及默认值,且Safari不支持该属性。
navigator.connection.rtt 是目前最实用、响应最快的网络质量信号,能直接反映当前链路的响应延迟。它比 effectiveType 更细粒度,比带宽估算更稳定,适合用来动态调节静态资源(如 JS/CSS/字体/图片)的并发加载数——但必须配合兜底和降级,否则在弱网或不支持环境下会失效。
RTT 不是线性指标,需按实际体验分段建模。关键不是“精确计算”,而是避免高 RTT 下盲目并发引发连接排队和超时堆积:
rtt <= 50ms:本地 Wi-Fi、有线、强 5G → 可设并发为 6–8,充分利用浏览器空闲连接槽位50ms < rtt <= 150ms:普通 4G、中等 Wi-Fi → 并发控制在 3–4,平衡吞吐与请求成功率rtt > 150ms:2G/3G、高抖动蜂窝、卫星链路 → 强制降为 1–2,防止预加载队列雪崩注意:rtt === 0 或 undefined 表示不可用,此时必须 fallback 到 navigator.connection.effectiveType 或默认值(如 3)。
不要在每次 fetch() 前临时读取 rtt,而应在初始化时建立响应式并发控制器,并监听 connection.change 事件更新:
const connection = navigator.connection;let concurrency = 4;if (connection && 'rtt' in connection) { const rtt = connection.rtt || 0; if (rtt <= 50) concurrency = 7; else if (rtt <= 150) concurrency = 4; else concurrency = 2;}// 监听变化(Chrome/Firefox 支持,Safari 不支持 change 事件)connection?.addEventListener('change', () => { const rtt = connection.rtt || 0; if (rtt <= 50) concurrency = 7; else if (rtt <= 150) concurrency = 4; else concurrency = 2;});
这个 concurrency 值应被传入你的资源加载队列管理器(如基于 Promise.allSettled + 限流的封装),而非硬编码进 fetch 调用里。
rtt 在以下场景会失效或误导:
rtt 属性,navigator.connection 只有 effectiveType 和 downlink
rtt 恒为 0,无法区分真实网络质量rtt = 120ms,若 effectiveType === 'slow-2g',仍应走弱网策略(运营商可能上报了错误的 RTT)所以实际逻辑应是:优先用 rtt 分段 → 若不可用或值异常,fallback 到 effectiveType → 最终 fallback 到固定默认值(如 3)。别让一个字段决定全部行为。
真正难的不是读取 rtt,而是把并发控制嵌入到已有加载流程中——比如 Webpack 的 import()、Vite 的 dynamic import、或自研的 CSS/Font 加载器。这些地方往往没有现成的“并发钩子”,得手动加节流层。漏掉一环,整个策略就形同虚设。