真正能用于带宽分级的是 downlink 和 rtt,再叠加 saveData;effectiveType 因模糊、滞后、兼容性差且无明确阈值,不适合作为资源分级依据。

不能只靠 navigator.connection.effectiveType 判断“网络等级”并下发资源——它太粗、太滞后、桌面端基本不可用。真正能用于带宽分级的,只有 downlink 和 rtt,再叠加 saveData 这个明确信号。
为什么 effectiveType 不适合做资源分级依据
effectiveType 是浏览器内部用 downlink + rtt 算出的一个模糊标签(比如 "4g" 或 "slow-2g"),但不暴露原始数值,也没提供阈值定义。实际中常见问题包括:
- Wi-Fi 信号弱但
downlink仍报 12 Mbps,effectiveType显示 "4g",结果视频卡顿 - iOS Safari 15.4 之前完全不支持该字段,拿到
undefined,直接 fallback 失败 - 桌面 Chrome 对
effectiveType的模拟逻辑和移动端不一致,开发时测不出来 - 即使值是 "3g",也可能是 3.2 Mbps(够播 720p)或 0.8 Mbps(只能播 240p),无法对应具体资源规格
用 downlink 和 rtt 组合判断真实带宽等级
downlink 单位是 Mbps,rtt 单位是 ms,两者结合比单独看任一值都稳。注意:安卓某些 WebView 会返回 downlink = 0,必须加安全判断。
- 强网:
downlink >= 8且rtt → 可加载高清图、WebP/AVIF、1080p 视频 - 中网:
downlink >= 1.5 && downlink 且 <code>rtt → 用 JPEG、720p、禁用懒加载首屏外图片 - 弱网:
downlink 或 <code>rtt > 300→ 强制降级为 SVG 占位、240p 视频、跳过所有非关键 fetch - 省流模式:
saveData === true→ 无条件触发最简策略(哪怕downlink显示 10),关闭埋点、禁用图片长按、不带 CDN 优化参数(如去掉?w=800&f=webp)
监听 change 事件时必须防抖 + 心跳校验
navigator.connection 的 change 事件可能在几秒内连发多次(比如 Wi-Fi 切 4G 的瞬间),直接响应会导致资源反复切换、请求中断、UI 闪动。
- 用 500ms 防抖包裹处理逻辑,等状态稳定再执行资源重排
- 仅靠 API 不足以确认“服务可用”——连得上 Wi-Fi 但 DNS 挂了、或内网能通但 API 域名解析失败,
connection依然返回正常值 - 每次 change 后,发起一次轻量
fetch('/health?ts='+Date.now()),超时设为 3s;仅当navigator.onLine === true且心跳成功,才认为“可用网络”成立 - 心跳失败时,降级到本地缓存,并提示“网络暂时不稳定,部分内容已离线加载”
真正的难点不在读取字段,而在把 downlink 和 rtt 的浮动值,映射成可落地的资源分发规则——它需要你提前定义好每档带宽对应的图片尺寸、视频码率、JSON 字段精简程度,并在切换时确保资源队列能安全中断与替换,而不是简单 reload 页面。

















