You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

方案关键点:

  1. 请求锁isFetching:彻底避免timeupdate高频触发导致的多请求冲突。
  2. Promise.race处理超时:精准控制3秒超时逻辑,超时立即暂停视频。
  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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 13:58:04