【问题标题】:Promise await blocking loop from finishing承诺等待阻塞循环完成
【发布时间】:2021-03-03 11:19:06
【问题描述】:

我需要一个循环来依次播放 10 个声音。我的第一次尝试声音重叠,所以我被告知我需要使用 Promise/await。下面的代码播放声音 0 然后永远不会继续循环。

(我使用的库(jscw)是用于莫尔斯电码的。你给它一个字符串,它会播放莫尔斯电码。它的“onFinished”调用一个用户定义的函数。)

async function playAll() {
  for (let i = 0; i < 10; i++) {
    playMorse(words[i]);
    await playstate();
  }
}

function playstate() {
  playdone = true;
  //console.log(playdone);
  return new Promise((resolve) => {
    window.addEventListener('playdone', resolve)
  })
}

function playMorse(z) {
  var m = new jscw();
  playdone = false;
  m.onFinished = function() {
    playstate();
  }
  m.play(z);
}

【问题讨论】:

  • 可能你的“游戏状态”永远不会得到解决,即使是第一次
  • 您知道您是否收到playdone 消息吗?这似乎可以从一些基本调试中受益,以查看正在发生的确切步骤(在代码的每个区域中放置 console.log() 语句),然后当您更明确地了解它卡在哪里时,我们可以为您提供更好的帮助。
  • 您的观察使playstate() 似乎永远不会解决它返回的承诺,如果从未收到playdone 事件就会发生这种情况,因此这绝对是第一个要调查的项目。此外,从 onFinished 处理程序调用 playstate() 对您没有好处。没有任何东西在使用这个承诺,无论如何在那时做addEventListener 可能为时已晚。您也可以只更改变量playdone 的状态,而不是从onFinished 调用playstate()
  • 此外,您正在为window.addEventListener('playdone', ...) 构建事件侦听器,而您永远不会删除这些侦听器。虽然在这种特殊情况下这不是灾难,但它是一种麻烦的编码方式,并且在其他情况下可能导致错误或内存泄漏。当你在一个持久的对象上完成了一个 eventListener 之后,你需要移除那个监听器。

标签: javascript async-await promise


【解决方案1】:

似乎什么都不应该触发您正在侦听的 playdone 事件。
所以一个简单的解决方案是在onFinished 回调中触发它。

const words = ["hello", "world"];
async function playAll() {
  for (let i = 0; i < 2; i++) {
    console.log("###READING", words[i]);
    playMorse(words[i]);
    await playstate();
  }
}

function playstate() {
  playdone = true;
  //console.log(playdone);
  return new Promise((resolve) => {
    window.addEventListener('playdone', resolve, { once: true })
  })
}

function playMorse(z) {
  var m = new jscw();
  playdone = false;
  m.onFinished = function() {
    dispatchEvent( new Event("playdone") );
  }
  m.play(z);
}

btn.onclick = playAll;
<script src="https://fkurz.net/ham/jscwlib/src/jscwlib.js"></script>
<button id="btn">play all</button>

但是你在这里不需要事件,只需让playMorse 返回一个将在onFinished 回调中解析的 Promise:

const words = ["hello", "world"];
async function playAll() {
  for (let i = 0; i < 2; i++) {
    console.log("###READING", words[i]);
    await playMorse(words[i]);
  }
}

function playMorse(z) {
  return new Promise( (resolve) => {
    const m = new jscw();
    m.onFinished = resolve;
    m.play(z);
  });
}

btn.onclick = playAll;
<script src="https://fkurz.net/ham/jscwlib/src/jscwlib.js"></script>
<button id="btn">play all</button>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-25
    • 2016-09-09
    • 2017-06-17
    • 2018-03-05
    • 2016-10-16
    相关资源
    最近更新 更多