Video.js播放时后端描述请求超时的视频启停处理方案咨询
Video.js播放时后端描述请求超时的视频启停处理方案咨询
看起来你已经搭好了Video.js和后端交互的基础逻辑,现在要解决的是请求描述超时(非视频缓冲)后暂停视频、请求完成后恢复播放的问题,我来帮你梳理下可行的方案,顺便优化下现有代码的小问题~
首先要注意:timeupdate事件触发频率非常高(每秒可能好几次),如果不加限制,会频繁发起后端请求,既浪费资源又可能导致逻辑混乱,所以第一步要加个「请求锁」,避免重复发起请求。
方案一:超时暂停+请求完成自动恢复(符合你的核心需求)
这个方案用Promise.race同时监听请求和3秒超时定时器,一旦超时就暂停视频;不管请求耗时多久,只要最终完成,就自动恢复视频播放。
修改后的完整代码如下:
const player = videojs('my-video'); let isFetching = false; // 请求锁:避免timeupdate频繁触发重复请求 let timeoutTimer = null; player.on('timeupdate', async function() { // 这里替换成你获取当前zone的逻辑,比如根据当前视频时间计算zone const zone = getCurrentVideoZone(this.currentTime()); if (isFetching) return; // 正在请求,直接跳过本次触发 isFetching = true; try { // 同时等待「请求完成」和「3秒超时」两个事件,谁先触发就执行谁 const [verset] = await Promise.race([ checkVerset(zone), new Promise((_, reject) => { timeoutTimer = setTimeout(() => { // 3秒超时,暂停视频 player.pause(); console.log('描述请求超时,已暂停视频'); reject(new Error('请求超时')); }, 3000); }) ]); // 如果请求在3秒内完成,清除超时定时器,避免误暂停 clearTimeout(timeoutTimer); // 这里写你拿到verset后的业务逻辑 console.log('成功获取描述:', verset); } catch (err) { // 只处理非超时的错误 if (err.message !== '请求超时') { console.error('请求出错:', err); } } finally { // 不管成功/失败/超时,都标记请求结束 isFetching = false; } }); async function checkVerset(zone) { try { const zoneRes = await connectFetch('./in.php', zone); console.log(zoneRes); // 如果视频因为超时被暂停,请求完成后自动恢复播放 if (player.paused()) { player.play(); console.log('描述请求完成,已恢复视频播放'); } return zoneRes; } catch (error) { console.log('请求详情错误:', error); // 如果请求出错,也可以根据业务需求决定是否恢复播放 if (player.paused()) { player.play(); } return null; } } async function connectFetch(url, text) { const response = await fetch(url, { method: 'post', mode: 'cors', credentials: 'same-origin', headers: {'Content-type': 'text/plain;charset=UTF-8'}, body: JSON.stringify(text) }); if (!response.ok) { // 注意用反引号解析变量,你之前的代码这里用了单引号会出错 const message = `Error: ${response.status}`; throw new Error(message); } return response.text(); } // 辅助函数:根据当前视频时间获取对应的zone(替换成你自己的逻辑) function getCurrentVideoZone(currentTime) { // 示例:每10秒一个zone return Math.floor(currentTime / 10); }
方案关键点:
- 请求锁
isFetching:彻底避免timeupdate高频触发导致的多请求冲突。 Promise.race处理超时:精准控制3秒超时逻辑,超时立即暂停视频。- 请求完成自动恢复:不管超时与否,只要后端返回结果,就自动恢复视频播放。
方案二:用AbortController中断超时请求(适合需要重试的场景)
如果你的需求是「超时后直接中断当前请求,后续可以重试」,那可以用AbortController来取消未完成的请求,避免不必要的资源占用。
核心修改是给fetch添加中断信号,超时后触发中断:
const player = videojs('my-video'); let isFetching = false; let abortController = null; let timeoutTimer = null; player.on('timeupdate', async function() { const zone = getCurrentVideoZone(this.currentTime()); if (isFetching) return; isFetching = true; abortController = new AbortController(); const signal = abortController.signal; try { const [verset] = await Promise.race([ checkVerset(zone, signal), new Promise((_, reject) => { timeoutTimer = setTimeout(() => { player.pause(); console.log('请求超时,已暂停视频并中断当前请求'); abortController.abort(); // 中断当前请求 reject(new Error('请求超时已中断')); }, 3000); }) ]); clearTimeout(timeoutTimer); console.log('成功获取描述:', verset); } catch (err) { if (err.name !== 'AbortError' && err.message !== '请求超时已中断') { console.error('请求出错:', err); } // 这里可以添加重试逻辑,比如1秒后重新发起请求 // setTimeout(() => checkVerset(zone, new AbortController().signal), 1000); } finally { isFetching = false; abortController = null; } }); // 给checkVerset和connectFetch添加signal参数 async function checkVerset(zone, signal) { try { const zoneRes = await connectFetch('./in.php', zone, signal); console.log(zoneRes); if (player.paused()) { player.play(); console.log('请求完成,恢复播放'); } return zoneRes; } catch (error) { if (error.name === 'AbortError') { console.log('请求已被中断'); } else { console.log('请求详情错误:', error); if (player.paused()) player.play(); } return null; } } async function connectFetch(url, text, signal) { const response = await fetch(url, { method: 'post', mode: 'cors', credentials: 'same-origin', headers: {'Content-type': 'text/plain;charset=UTF-8'}, body: JSON.stringify(text), signal: signal // 绑定中断信号 }); if (!response.ok) { const message = `Error: ${response.status}`; throw new Error(message); } return response.text(); }
总结建议
- 如果你只是想超时暂停、请求完成就恢复,优先选方案一,逻辑更简单直接,符合你的核心需求。
- 如果你需要超时后中断请求、后续可能重试,再考虑方案二。
- 无论哪个方案,「请求锁」都是必须的,否则
timeupdate的高频触发会让你的逻辑彻底混乱。
备注:内容来源于stack exchange,提问作者kam
相关产品推荐
相关产品推荐

