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

如何实现Promise终止以跳过浏览器点唱机的当前音频?

问题分析与解决方案

你的核心问题是AbortController没有和播放音频的Promise建立关联,也没在音频播放过程中监听终止信号,同时缺少终止后停止音频播放的逻辑。以下是具体修复步骤:

1. 传递并监听AbortSignal

需要把AbortController的signal传递到jukebox和playSound函数中,让Promise能响应终止信号:

修改jukebox函数

传入signal并在循环内处理终止逻辑:

// 调用jukebox时传入signal
jukebox({ signal: ac.signal });

async function jukebox({ signal } = {}) {
  var jbsong = '';
  var maxSongs = 5;
  jbplays = true;
  for (var j = 0; j < maxSongs; j++) {
    // 若信号已终止,可提前退出循环(可选)
    if (signal?.aborted) break;
    
    jbsong = getRandomSong();
    try {
      // 把signal传递给playSound
      const answer = await playSound(jbsong, signal);
    } catch (playerror) {
      // 区分终止信号和音频错误
      if (playerror.name === 'AbortError') {
        console.log("跳过当前歌曲");
        // 终止后直接进入下一首循环
        continue;
      }
      console.log(j + ". NOT found: " + jbsong);
      console.log("PlayError: " + playerror);
    }
  }
  jbplays = false;
  stopMedia();
  console.log("Jukebox Finished");
};

修改playSound函数

让Promise监听终止信号,触发时停止音频并reject:

function playSound(soundfile, signal) { 
  audio.src = soundfile;
  if (jbplays) {
    return new Promise(function(resolve, reject) {
      // 原有音频事件监听
      audio.onerror = () => reject(new Error("音频加载失败"));
      audio.onended = resolve;

      // 监听终止信号
      if (signal) {
        // 若信号已提前终止,直接停止音频并reject
        if (signal.aborted) {
          audio.pause();
          audio.currentTime = 0;
          return reject(new DOMException("播放被终止", "AbortError"));
        }

        // 添加终止监听回调
        const onAbort = () => {
          audio.pause();
          audio.currentTime = 0;
          reject(new DOMException("播放被终止", "AbortError"));
          // 移除监听避免内存泄漏
          signal.removeEventListener('abort', onAbort);
        };
        signal.addEventListener('abort', onAbort);
      }
    })
  } else {
    // 单首播放逻辑保持不变
    …
  }
};  

2. 终止逻辑说明

按下S键调用ac.abort()时,当前playSound的Promise会被reject,进入catch块后通过判断AbortError类型,执行continue让循环直接进入下一首,实现“跳过”效果。同时audio.pause()和audio.currentTime = 0会立即停止当前音频并重置播放位置,避免后台播放。

3. 额外注意

如果需要支持多次跳过,每次启动jukebox前建议创建新的AbortController实例,避免旧的终止信号干扰新的播放流程。

内容的提问来源于stack exchange,提问作者R.E. Tired

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 22:45:27