preload="none"仍发起网络请求是因为浏览器将其视为建议而非指令,Chrome会在插入DOM后、首次交互前预取前几KB以优化首播延迟。

preload="none" 为什么 still 发起网络请求?
浏览器把 preload 当作建议而非指令,preload="none" 并不等于“完全不碰网络”。Chrome 桌面版在元素插入 DOM 后、用户首次交互前,仍可能预取前几 KB(如 ID3 头、ADTS 帧),只为加速后续 play() 响应。这不是 bug,是权衡首播延迟与带宽的实现策略。
这种预取行为受以下条件抑制:
- 页面未获得焦点(比如后台标签页)
- 设备启用 Low Data Mode
- 服务端响应头缺失
Content-Length或声明Accept-Ranges: none - audio 元素未挂载到 DOM 就设置
src(此时 preload 不触发)
iOS Safari 则更彻底:无论设成 auto 还是 metadata,都只加载元数据(时长、码率、封面),且绝不会预取音频帧——这是硬性限制,不是你配置错了。
动态设置 src 后 preload 不生效?必须调用 load()
preload 只在元素插入 DOM 且 src 已存在时做一次加载决策。JS 动态赋值 audio.src = 'a.mp3' 不会重新触发该逻辑。
立即学习“前端免费学习笔记(深入)”;
正确做法是显式调用 audio.load():
- 多次调用
load()无副作用,但仅当当前状态不是loadedmetadata时才真正发起加载 - 修改
preload值本身(比如从none改为auto)不会触发重加载,必须配合load()或重置src - 若用
fetch+arrayBuffer手动加载,preload完全无关,控制权已在 JS 层
autoplay 和 controls 如何影响 preload 实际效果?
autoplay 的优先级高于 preload。只要写了 autoplay,浏览器会无视 preload 值,直接开始下载媒体以供播放——但现代浏览器普遍要求静音(muted)或用户已交互,否则会静默拦截。
controls 属性则悄悄推动浏览器走 metadata 路径:因为进度条、时长显示依赖元数据,而不是完整文件。哪怕你设了 preload="auto",只要加了 controls,桌面 Chrome 往往只加载前几秒;而 iOS Safari 依然只取元数据。
真正决定首播延迟的,从来不是 preload 值本身,而是它是否落在浏览器愿意执行的上下文中:
- DOM 已挂载
- 用户有过交互(点击、触摸等)
- 网络可用(非离线/低数据模式)
- 服务端支持范围请求(
Accept-Ranges: bytes) - 没被 autoplay 策略或 controls UI 干扰
MP3 / OGG / WAV 格式选择与兼容性陷阱
不同浏览器对音频格式的支持差异至今未统一。MP3 在 Chrome、Safari、IE9+ 中通吃,但 Firefox 和 Opera 不支持;OGG 在 Firefox、Chrome、Opera 中表现好,Safari 却完全拒绝;WAV 音质高但体积大,且 Chrome、Safari、IE9+ 均不支持。
最稳妥的写法是用 source 元素提供 fallback:
<audio controls> <source src="song.mp3" type="audio/mpeg"> <source src="song.ogg" type="audio/ogg"> 您的浏览器不支持 audio 元素。 </audio>
注意:type 属性不是可选的——它帮助浏览器跳过不支持的格式,避免无谓的 404 请求。漏掉它,某些浏览器会尝试加载所有 source,拖慢解析和首播。
压缩比和首播体验也有关:同等音质下,OGG 通常比 MP3 小 10–15%,但 Safari 用户根本听不到;MP3 兼容性最好,适合多数场景;WAV 仅建议用于极短提示音(如按钮反馈),否则首帧加载延迟明显。



















