audio.duration初始为nan是正常现象,因元数据未加载完成;须监听loadedmetadata事件,在回调中用isfinite()判断后读取并格式化。

audio.duration 为什么总是 NaN?
直接读 audio.duration 很大概率拿到 NaN,不是代码写错了,而是音频还没加载元数据(metadata)。浏览器必须先解析文件头,才知道时长,这个过程异步发生,且受网络、格式、CORS 等影响。
常见错误现象:audio.duration 在 DOMContentLoaded 里读是 NaN;用 audio.src = 'xxx.mp3' 赋值后立刻读,也是 NaN。
- 必须监听
loadedmetadata事件,在回调里读duration - 如果音频已缓存或本地文件,有时
duration会提前就绪,但绝不能依赖这种“巧合” - 若音频跨域(比如 CDN 上的 MP3),服务端没配
Access-Control-Allow-Origin,loadedmetadata根本不会触发,duration永远不可读
如何可靠获取并展示总时长?
核心是等 loadedmetadata,再格式化秒数为 MM:SS。注意:duration 是浮点数(单位秒),可能为 Infinity(流式音频无明确终点)或负值(加载失败)。
const audio = document.querySelector('audio');
audio.addEventListener('loadedmetadata', () => {
if (isFinite(audio.duration)) {
const total = Math.floor(audio.duration);
const min = Math.floor(total / 60);
const sec = total % 60;
document.getElementById('duration').textContent = `${min}:${sec.toString().padStart(2, '0')}`;
}
});
- 务必用
isFinite()判断,过滤NaN和Infinity -
Math.floor()防止小数秒导致显示异常(如3:60) - 不要用
timeupdate事件来“轮询”duration——它只在播放中触发,且不保证duration已就绪
audio.readyState 和 networkState 的实际意义
duration 就绪与否,和 readyState 强相关。只有 readyState >= HTMLMediaElement.HAVE_METADATA(即值 ≥ 1)时,duration 才可信。
-
audio.readyState === 0:还没开始加载,duration必为NaN -
readyState === 1:已获取元数据(含时长),可安全读duration -
networkState === HTMLMediaElement.NETWORK_NO_SOURCE表示src为空或无效,此时loadedmetadata永远不会触发 - 调试时可打印
audio.readyState和audio.networkState辅助定位卡在哪一步
MP3/MP4/WAV 的兼容性差异
不是所有格式都能被所有浏览器正确解析出时长。MP3 在 Safari 中曾长期存在 duration 为 NaN 的问题(尤其无 ID3v2 或帧头损坏);WAV 通常没问题但体积大;MP4(AAC + H.264 容器)最稳定。
- 服务端转码时,确保 MP3 包含合法的 Xing/VBRI 头,或用 FFmpeg 加
-write_xing 1 - 开发阶段优先用 MP4 测试,避免被格式坑住
- 移动端 WebView(如微信内置浏览器)对某些 MP3 的
loadedmetadata触发更迟缓,建议加超时 fallback(例如 5 秒后若仍无duration,显示 “未知时长”)
真正麻烦的从来不是怎么把秒数转成 MM:SS,而是怎么确认那个数字真的存在、准确、且能被当前环境读出来——元数据加载这一步,藏了太多隐性依赖。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











