仅在加载指定音频数据后重新执行while循环的实现问题
问题根因
你的推测是正确的,还有几处额外的问题共同导致了当前结果:
- 同步执行的
while循环不会等待异步的loadedmetadata事件触发,循环会在毫秒级跑完所有迭代,所有音频加载请求几乎同时发出 - 全局复用同一个
audio元素,每次修改src会覆盖上一个资源地址,事件触发时读取的au.duration永远是最后一个加载完成的音频的时长 - 事件回调存在闭包问题,回调执行时循环变量
i已经迭代到最终值,无法和每个音频一一对应
解决方法
我们可以把单个音频时长获取逻辑封装成Promise,配合async/await实现串行加载,保证上一个音频加载完成、拿到时长后再进入下一轮迭代:
const myList = [ 'https://mixergy.com/wp-content/audio/Nick-Bolton-Animas-on-Mixergy0721.mp3', 'https://episodes.castos.com/5e7027dcc7b720-84196812/MicroCOnf-on-Air-Refresh.Ep.6.mp3' ]; // 存储所有音频时长的数组 const audioDurations = []; // 封装单个音频时长获取的Promise function getAudioDuration(url) { return new Promise((resolve, reject) => { const au = document.createElement('audio'); au.src = url; // 元数据加载成功后返回时长 au.addEventListener('loadedmetadata', () => { const duration = Math.round(au.duration); resolve(duration); }, false); // 加载失败的兜底 au.addEventListener('error', (err) => { reject(err); }, false); }) } // 串行加载所有音频获取时长 async function loadAllAudioDurations() { for(let i = 0; i < myList.length; i++) { try { const duration = await getAudioDuration(myList[i]); audioDurations.push(duration); console.log(`第${i+1}个音频时长:${duration}秒`); } catch(e) { console.log(`第${i+1}个音频加载失败:`, e); audioDurations.push(null); } } // 所有音频加载完成后输出总结果 console.log('所有音频时长:', audioDurations); } // 执行加载逻辑 loadAllAudioDurations();
你原有HTML代码不需要做任何修改,直接替换JS文件的逻辑即可。
内容的提问来源于stack exchange,提问作者jiblylabs
相关产品推荐
相关产品推荐

