Foreach循环中变量hh存储的音频文件时长获取返回NaN问题求助
问题
在forEach循环中尝试获取存储在变量hh中的音频文件时长时,返回NaN而非预期值。音频文件已确认有效且可访问,但直接访问hh.duration始终得到NaN。简化代码如下:
function showcontent() { let songsarra = localStorage.getItem("Songs"); let songa = JSON.parse(songsarra); document.getElementById("SongItemContainer").innerHTML = ""; let x = 0; let index = 0; songa.forEach(()=>{ let hh = new Audio(songa[x].filepath); document.getElementById("SongItemContainer").innerHTML += `<div class="songItem"> <img src="${songa[x].Coverpath}" alt=""> <span class="songname">${songa[x].songName}</span> <span class="timestamp">${hh.duration} <i class="fa-regular fa-trash-can delete" onclick="deleteitem(${index})"></i> <i class="fa-regular fa-circle-play current" id="${x}"></i></span> </div>`; x++; index++; }); }
原因与解决方案
问题根源
Audio对象的duration属性依赖于音频元数据的加载,创建Audio实例后立即访问duration时,元数据还未加载完成,因此返回NaN。
解决方法
1. 监听loadedmetadata事件获取时长
为每个Audio实例绑定loadedmetadata事件,待元数据加载完成后再更新DOM中的时长信息:
function showcontent() { let songsarra = localStorage.getItem("Songs"); let songa = JSON.parse(songsarra); const container = document.getElementById("SongItemContainer"); container.innerHTML = ""; songa.forEach((song, idx) => { // 先创建并添加基础DOM元素 const songItem = document.createElement("div"); songItem.className = "songItem"; songItem.innerHTML = ` <img src="${song.Coverpath}" alt=""> <span class="songname">${song.songName}</span> <span class="timestamp">加载中... <i class="fa-regular fa-trash-can delete" onclick="deleteitem(${idx})"></i> <i class="fa-regular fa-circle-play current" id="${idx}"></i></span> `; container.appendChild(songItem); // 创建Audio实例并监听元数据加载事件 const audio = new Audio(song.filepath); audio.addEventListener("loadedmetadata", () => { // 格式化时长为MM:SS格式(可选) const minutes = Math.floor(audio.duration / 60); const seconds = Math.floor(audio.duration % 60); const formattedDuration = `${minutes}:${seconds.toString().padStart(2, "0")}`; // 更新对应的时长元素 songItem.querySelector(".timestamp").innerHTML = `${formattedDuration} <i class="fa-regular fa-trash-can delete" onclick="deleteitem(${idx})"></i> <i class="fa-regular fa-circle-play current" id="${idx}"></i>`; }); // 处理音频加载失败的情况 audio.addEventListener("error", () => { songItem.querySelector(".timestamp").innerHTML = `加载失败 <i class="fa-regular fa-trash-can delete" onclick="deleteitem(${idx})"></i> <i class="fa-regular fa-circle-play current" id="${idx}"></i>`; }); }); }
2. 优化循环写法
原代码中x和index变量完全多余,直接利用forEach的第二个参数(当前元素索引)即可,简化代码逻辑。
3. 避免频繁修改innerHTML
频繁拼接innerHTML会导致DOM反复重绘,性能较差,改用createElement和appendChild的方式更高效。
内容的提问来源于stack exchange,提问作者user22192978
相关产品推荐
相关产品推荐

