You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:08:32