【问题标题】:Using while (true) in async?在异步中使用while(true)?
【发布时间】:2021-07-29 16:30:21
【问题描述】:

我有一个需要持续执行的 Javascript 任务。我有一个存储为缓冲区(audioBuffer)的音频文件列表,我想播放。但是,该列表中不断附加音频文件,因此我使用了一个 while 循环来监视它。我不断地得到第一个缓冲区,播放它的音频,然后将它出列。但是,当我运行此函数时,它会使我的浏览器挂起,即使循环位于异步包装器中。为什么是这样? async 不应该在很大程度上防止我的浏览器死机吗?

代码:

function playAudioQueue() {
                const player = new Audio();

                (async () => {
                  while (true) {
                    const audioBuffer = audioQueue[0];

                    if (audioBuffer) {
                      const base64Audio = base64Prefix + arrayBufferToBase64(audioBuffer);

                      player.src = base64Audio;

                      await player.play();

                      audioQueue.shift();
                    };
                  };
                })();
              };

【问题讨论】:

  • 代码没有意义,你到底想完成什么。
  • @epascarello 我在帖子中说。我有一个存储为缓冲区的音频文件列表,我想播放。但是,该列表中会不断附加音频文件,因此我使用了一个 while 循环来监视它。
  • 播放不是异步的,所以不确定你在期待什么。最好使用一个不同的模型,其中一个事件触发说添加了一些东西,如果你能做到这一点,你需要一种更好的方法来监控正在添加的东西,因为无限的 while 循环只会锁定浏览器。跨度>

标签: javascript loops asynchronous


【解决方案1】:

您基本上是在创建一个无限循环。它将锁定浏览器。您基本上需要做一个队列类型的事情,它在不使用循环的情况下不断检查。您可以使用ended 知道文件何时播放完毕

const audioQueue = [];

function playNext() {
  // grab the next thing to play
  const nextFile = audioQueue.shift();

  // if nothing there, check again in a short time
  if (!nextFile) {
    window.setTimeout(playNext, 1);
    return;
  }

  // Create a new player
  const player = new Audio();
  const base64Audio = base64Prefix + arrayBufferToBase64(nextFile);

  // when done, load up next thing to play
  player.addEventListener("ended", playNext);
  player.src = base64Audio;
  player.play();
}

playNext();

【讨论】:

  • 我也试试这个,谢谢回答!
  • 请注意,您不断为每首歌曲添加一个事件监听器,这将导致您在第二首歌曲之后跳过歌曲。
  • @KelvinSchoofs 每次都是播放器的新实例。我没有使用一个实例。我本可以这样做,但没有。
  • 啊,真的。尽管如此,每次通话都会创建一个新的Audio,尽管我想这没什么大不了的。
【解决方案2】:

根据MDN Web Docs

一个Promise,在播放开始时被解析,或者如果由于任何原因无法开始播放,则被拒绝。

一个问题可能是在您的浏览器中它会立即解决,因为您使用的是data: URL,它不需要等待任何网络请求。

您的代码中更大的逻辑问题是您似乎期望await player.play() 会等到歌曲播放完毕。情况不是,很可能不是您所期望的。

【讨论】:

  • 哦,player.play() 立即解决。我想我应该改用 audio.onended 。谢谢!
  • 你可以做类似await new Promise(r => audio.addEventListener(r, { once: true }))的事情。 IIRC 这是让addEventListener 在第一次触发后自动取消注册处理程序的正确方法。
  • @Crupeng 另外不要忘记将此答案标记为您问题的解决方案。
  • 我会尝试看看它是否有效,我现在将这些建议放入我的代码中。我检查后标记。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-15
  • 2017-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-01
  • 1970-01-01
相关资源
最近更新 更多