JavaScript中for循环获取音频时长值偶尔显示为NaN的问题
这问题我之前也碰到过!核心原因很简单:你访问audio.duration的时候,音频的元数据(包括时长信息)还没被浏览器加载完成,所以才会随机返回NaN——有时候网络快,元数据提前加载好了就正常,慢的话就出问题。而点击触发时,通常已经过了足够时间,元数据早就加载完了,所以一切正常。
接下来给你两种靠谱的解决方案:
方案一:监听单个音频的loadedmetadata事件
这个事件是浏览器专门为媒体元素设计的,当它获取到足够的元数据(比如时长、编码格式)时就会触发,这时候去读duration绝对是有效值。
修改后的代码如下:
// 先获取你的音频列表(假设playList是已经获取到的audio元素集合) const playList = document.querySelectorAll('audio'); // 把计算和显示时长的逻辑抽成单独函数,复用性更好 function showAudioDuration(audioEl) { let minutes = Math.floor(audioEl.duration / 60); let seconds = Math.ceil(audioEl.duration % 60); // 补零处理,让格式更统一 minutes = minutes < 10 ? `0${minutes}` : minutes; seconds = seconds < 10 ? `0${seconds}` : seconds; const durationPara = document.createElement('p'); durationPara.className = "totalDuration"; durationPara.textContent = `${minutes}:${seconds}`; audioEl.parentElement.appendChild(durationPara); } // 遍历每个音频元素处理 playList.forEach(audio => { // 先判断一下,如果音频已经缓存过,元数据已经加载完成,直接处理 if (audio.duration > 0) { showAudioDuration(audio); } else { // 否则等待元数据加载完成 audio.addEventListener('loadedmetadata', () => { showAudioDuration(audio); }); } });
方案二:用Promise.all等待所有音频元数据加载完成
如果你需要等所有音频都准备好再统一处理(比如还要计算总时长总和),这种方式会更合适:
const playList = document.querySelectorAll('audio'); // 把每个音频的元数据加载过程转成Promise const metadataReadyPromises = Array.from(playList).map(audio => { return new Promise(resolve => { if (audio.duration > 0) { resolve(audio); } else { audio.addEventListener('loadedmetadata', () => resolve(audio)); } }); }); // 等待所有音频元数据都加载完成后再批量处理 Promise.all(metadataReadyPromises).then(allAudios => { allAudios.forEach(audio => { let minutes = Math.floor(audio.duration / 60); let seconds = Math.ceil(audio.duration % 60); minutes = minutes < 10 ? `0${minutes}` : minutes; seconds = seconds < 10 ? `0${seconds}` : seconds; const durationPara = document.createElement('p'); durationPara.className = "totalDuration"; durationPara.textContent = `${minutes}:${seconds}`; audio.parentElement.appendChild(durationPara); }); });
补充说明
为什么之前放在window.onload或全局作用域不行?因为window.onload只是等待页面所有资源(包括音频文件)下载完成,但浏览器可能在下载完音频文件的同时,还没解析出元数据;或者受缓存、网络波动影响,元数据加载的时机不稳定。而loadedmetadata是专门针对元数据加载完成的事件,比window.onload精准得多,能彻底解决这个随机NaN的问题。
内容的提问来源于stack exchange,提问作者Vo_
相关产品推荐
相关产品推荐

