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

JavaScript音频播放异常:切换至SUCCESS状态后音频仍持续播放

解决音频在SUCCESS状态下无法停止的问题

问题根源

  1. 定时器引用丢失:audioInterval是xState函数的局部变量,每次调用函数都会重新初始化audioInterval = null,导致无法获取DANGER状态下创建的定时器引用,无法清除定时播放逻辑,音频会持续重复播放。
  2. 冗余无效代码:SUCCESS分支里嵌套了重复的if (status === statesName.SUCCESS)判断,属于多余代码,不影响逻辑但增加冗余。

修复方案

1. 持久化存储定时器引用

新增全局/模块级变量存储每个状态对应的定时器,确保每次调用xState都能获取到对应状态的定时器实例:

const audioStates = { Head: false, Body: false, Distance: false, Height: false };
const audioIntervals = { Head: null, Body: null, Distance: null, Height: null }; // 新增定时器存储对象

2. 修改xState函数逻辑

替换函数内的audioInterval引用为audioIntervals[name],并移除冗余判断:

const xState = ({
  name,
  value,
  threshold,
  timer,
  currentState,
  currentStateTimeStamp,
  cbCurrentStateTimeStamp,
  cbChange,
  toastMsgSuccess,
  toastMsgDanger,
}) => {
  let status = statesName.SUCCESS;

  if (value <= threshold) {
    timer.reset();
    status = statesName.SUCCESS;
  } else if (value > threshold) {
    timer.start({ precision: 'secondTenths' });
    if (
      timer.getTotalTimeValues().seconds >
      appContext.timer_timeUntilBadPosture
    ) {
      status = statesName.DANGER;
    } else {
      status = statesName.WARNING;
    }
  }

  function playAudioForState(state) {
    switch (state) {
      case 'Head':
        dangerAudioHead.play();
        break;
      case 'Body':
        dangerAudioBody.play();
        break;
      case 'Distance':
        dangerAudioDistance.play();
        break;
      case 'Height':
        dangerAudioHeight.play();
        break;
      default:
        break;
    }
    audioStates[name] = true;
  }

  function stopAudioForState(state) {
    switch (state) {
      case 'Head':
        dangerAudioHead.pause();
        dangerAudioHead.currentTime = 0;
        break;
      case 'Body':
        dangerAudioBody.pause();
        dangerAudioBody.currentTime = 0;
        break;
      case 'Distance':
        dangerAudioDistance.pause();
        dangerAudioDistance.currentTime = 0;
        break;
      case 'Height':
        dangerAudioHeight.pause();
        dangerAudioHeight.currentTime = 0;
        break;
      default:
        break;
    }
    audioStates[name] = false;
  }

  if (currentState !== status) {
    setTimelineData([
      ...timelineData,
      [
        name,
        currentState,
        statesColourHex[currentState],
        currentStateTimeStamp,
        nextObj.createdAt,
      ],
    ]);
    cbCurrentStateTimeStamp(nextObj.createdAt);

    if (status === statesName.SUCCESS) {
      stopAudioForState(name);
      audioStates[name] = false;
      showToast(toastMsgSuccess, Intent.SUCCESS);
      // 清除对应状态的定时器
      if (audioIntervals[name] !== null) {
        clearInterval(audioIntervals[name]);
        audioIntervals[name] = null;
      }
    } else if (status === statesName.DANGER) {
      if (!audioIntervals[name] && !audioStates[name]) {
        audioStates[name] = true;
        playAudioForState(name);
        audioIntervals[name] = setInterval(() => {
          playAudioForState(name);
        }, 3000);
      }
      showToast(toastMsgDanger, Intent.DANGER);
    } else if (status === statesName.WARNING) {
      if (audioIntervals[name] !== null) {
        clearInterval(audioIntervals[name]);
        audioIntervals[name] = null;
      }
    }
    cbChange(status);
  }
};

3. 额外验证点

  • 切换到SUCCESS状态后,检查对应音频元素是否已暂停并重置播放位置
  • 确认audioIntervals[name]已被重置为null,定时器不再触发

内容的提问来源于stack exchange,提问作者xenturion 666

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 10:43:26