JS开发MP3随机播放器时歌曲同步播放、页面崩溃该如何解决?
问题原因
JavaScript的同步循环不会等待异步操作完成:for循环会在几毫秒内全部执行完毕,而音频播放是异步任务,不会阻塞循环执行,所以会同时触发多次播放逻辑,最终导致页面崩溃。
另外你贴的代码存在多处基础语法错误:函数关键字funcion拼写错误、音乐地址引号不配对、直接对字符串数组调用play方法、随机数范围越界,都需要先修正。
解决方案
不要用同步for循环控制播放顺序,改用音频的ended事件触发下一首播放,或者用Promise+async/await封装播放等待逻辑,两种可运行的实现方案如下:
方案1:事件驱动递归实现(兼容性更好)
// 先将音乐地址实例化为Audio对象数组 const musicList = [ new Audio('https://samplelib.com/lib/preview/mp3/sample-3s.mp3'), new Audio('https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3') ]; // 配置需要连续播放的总数量 const TOTAL_PLAY = 4; // 记录当前已播放次数 let playedCount = 0; function playNext() { // 达到播放数量直接终止 if (playedCount >= TOTAL_PLAY) return; // 生成和数组长度匹配的随机下标,避免越界 const randomIndex = Math.floor(Math.random() * musicList.length); const currentMusic = musicList[randomIndex]; // 播放当前选中音乐 currentMusic.play(); playedCount++; // 监听播放结束事件,结束后自动播放下一首 currentMusic.addEventListener('ended', function onEnd() { // 移除监听器避免重复绑定 currentMusic.removeEventListener('ended', onEnd); playNext(); }); } // 按钮点击触发播放逻辑 function buttonClick() { // 重置计数,每次点击重新开始播4首随机歌 playedCount = 0; playNext(); }
方案2:async/await 封装实现(逻辑更直观)
const musicList = [ new Audio('https://samplelib.com/lib/preview/mp3/sample-3s.mp3'), new Audio('https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3') ]; // 封装单首音乐播放为Promise,播放完成后自动resolve function playSingleMusic(music) { return new Promise((resolve) => { music.play(); music.addEventListener('ended', function onEnd() { music.removeEventListener('ended', onEnd); resolve(); }); }); } // async函数实现循环等待逻辑 async function startRandomPlay(total = 4) { for (let i = 0; i < total; i++) { const randomIndex = Math.floor(Math.random() * musicList.length); // 等待当前音乐播放完成才会进入下一次循环 await playSingleMusic(musicList[randomIndex]); console.log(`第${i + 1}首播放完成`); } } // 按钮点击触发 function buttonClick() { startRandomPlay(4); }
注意事项
- 随机数生成要和数组长度绑定,不要写死固定数值,避免数组元素数量变化时出现下标越界报错
- 每次绑定
ended事件后要在触发后及时移除,避免同一个音频对象绑定多个重复监听器导致内存泄漏 - 音频资源必须先实例化为
Audio对象才能调用play方法,不能直接对存储地址的字符串调用播放接口
内容的提问来源于stack exchange,提问作者Arisyn ILY
相关产品推荐
相关产品推荐

