视频源排队函数意外跳过数组元素:问题排查与修复
问题分析与修复方案
问题根源
- 重复绑定事件导致逻辑混乱:每次调用
test()时,都会在setInterval里重复给#player绑定timeupdate事件,随着循环执行会堆积大量事件监听。第一个视频结束触发test()后,旧的监听仍在运行,会误判第二个视频的播放状态,直接触发下一轮播放跳过第二个视频。 - 视频结束判断逻辑不可靠:用
currentTime == duration判断视频结束,会受timeupdate触发时机、浮点精度影响,大概率无法精准匹配,要么触发失效要么误触发。 - 过早修改播放队列:在
loadedmetadata事件里就移除数组首个元素,此时视频还未播放,若加载失败会直接丢失该视频资源。 - 冗余定时器嵌套:用
setInterval包裹事件绑定完全没必要,反而加剧了重复绑定的问题。
修复后的代码
核心优化:使用视频原生ended事件监听播放结束,避免重复绑定,调整队列修改时机,简化逻辑。
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <video id="player" muted autoplay></video>
video { width: 100%; height: 60vh; }
const videoQueue = ["http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4", "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4", "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4"]; const $player = $('#player'); function playNext() { if (videoQueue.length === 0) { console.log('所有视频播放完毕'); $player.off('ended'); return; } // 先移除旧的事件监听,避免重复绑定 $player.off('ended'); // 设置当前播放源 $player.attr('src', videoQueue[0]); // 绑定原生播放结束事件 $player.on('ended', function() { // 确认播放完成后再移除队列首元素 videoQueue.shift(); playNext(); }); } // 启动播放队列 playNext();
关键优化说明
- 用
ended事件替代自定义判断:这是浏览器为video元素提供的原生事件,会在视频播放完成时精准触发,彻底规避自定义判断的精度和时机问题。 - 避免事件监听堆积:每次启动新视频前,先移除之前的
ended监听,防止多个监听同时触发导致逻辑混乱。 - 合理修改队列时机:只有在视频确实播放完成后,才从队列中移除对应资源,避免加载失败导致视频丢失。
- 简化逻辑结构:去掉冗余的定时器和不必要的事件嵌套,代码逻辑更清晰易维护。
内容的提问来源于stack exchange,提问作者seriously
相关产品推荐
相关产品推荐

