【问题标题】:Resolve a promise inside a promise在 Promise 中解决 Promise
【发布时间】:2020-08-06 16:05:44
【问题描述】:

我遇到了一个问题,我有一个 react-native 应用程序,我有一组动作来显示视频(我之前记录了这些动作)。

我对所有操作都有一个 for 循环,需要等待视频达到某个时间戳才能触发操作。为此,我使用一个开关来识别我的所有操作,并在内部等待一个承诺,以便在良好的时间戳触发操作。

这是我的代码:

  isTimestampReached = (timestampToWait) => {
    console.log(
      `timestampToWait: ', ${timestampToWait}, currentTime: ${this.videoPlayerRef.controlButtonRef.getCurrentTime()}`,
    );
    return new Promise((resolve, reject) => {
      if (
        timestampToWait <
          this.videoPlayerRef.controlButtonRef.getCurrentTime() + 0.05 &&
        timestampToWait >
          this.videoPlayerRef.controlButtonRef.getCurrentTime() - 0.05
      ) {
        console.log('timestamp Reached !');
        resolve(true);
      } else {
        setTimeout(this.isTimestampReached, 100, timestampToWait);
      }
    });
  };

  previewRecording = async () => {
    this.resetPlayer();
    const {recordedActions} = this.state;
    console.log('recordedActions: ', recordedActions);
    for (const action of recordedActions) {
      console.log('action', action);
      switch (action.type) {
        case 'play':
          console.log('launch play');
          // if (await this.isTimestampReached(action.timestamp)) {  // this is the same as the line under
          await this.isTimestampReached(action.timestamp).then(() => {
            this.videoPlayerRef.setState({
              paused: false,
            });
            console.log('setPlay');
          });
          break;
        case 'pause':
          console.log('launch pause');
          await this.isTimestampReached(action.timestamp).then(() => {
            console.log('set Pause');
            this.videoPlayerRef.setState({
              paused: true,
            });
          }),
            console.log('pause outside loop');
          break;
        case 'changePlayRate':
          console.log('changePlayRate');
          this.videoPlayerRef.setState({
            playRate: action.playRate,
          });
          break;
        default:
          console.log(`case ${action.type} not handled`);
      }
    }
  };

和日志:

我们可以看到我留在 for loop 和 switch 内,因为我没有得到 console.log('pause outside loop'); 。但正如你所见,我也没有得到console.log('set Pause');。所以这意味着我的 Promise 没有解决。

我认为问题在于在 Promise 中启动 Promise,因为对于第一种情况(播放)它直接起作用。但我不知道如何解决这个问题。

提前感谢社区

PS:我只放了 javascript 标签,因为我认为这与 react 或 react-native 无关。

【问题讨论】:

  • 你为什么需要然后你可以保持等待,只是让你的更新状态低于等待
  • 不要在isTimestampReached 中使用轮询(在else 的情况下,您完全忘记了解决您的承诺)!改为收听timeupdate event。
  • 哦,我错过了您使用的是 react-native 而不是 html5 媒体 api。你用的是什么库,它不会为currentTime的变化发出事件吗?
  • 我正在使用 react-native-video 并且我可以在来自文档的时间是(onProgress)时进行回调:github.com/react-native-community/react-native-video#onprogress,您是否想到了一种更清洁的方法来做到这一点@Bergi ?
  • @foufrix 我会做类似new Promise(resolve =&gt; { element.addEventListener('timeupdate', function checkTime(e) { if (e.currentTime &lt; timeStampToWait) { resolve(); element.removeEventListener('timeupdate', checkTime); } }); /* maybe also some error handlng */ }) 的事情,但我不知道如何在反应道具中安装/卸载事件监听器。

标签: javascript


【解决方案1】:

这意味着我的 Promise 没有解决。我认为问题在于在 Promise 中启动 Promise。

确实如此。在new Promise 的执行器回调中,您只调用setTimeout,但从不调用resolve() 或reject()。 isTimestampReached 100 毫秒后的调用确实创建并返回了它自己的承诺,原来的“外部”承诺永远不会被解决。你可以通过这样做来解决这个问题

setTimeout(() => {
  resolve(this.isTimestampReached(timestampToWait);
}, 100);

但是使用async/await 进行轮询要容易得多:

async isTimestampReached(timestampToWait) {
  while (true) {
    const currentTime = this.videoPlayerRef.controlButtonRef.getCurrentTime();
    console.log(`timestampToWait: ${timestampToWait}, currentTime: ${currentTime}`);
    if (timestampToWait < currentTime + 0.05 &&
        timestampToWait > currentTime - 0.05) {
      console.log('timestamp Reached !');
      return true;
    }
    await new Promise(resolve => {
      setTimeout(resolve, 100);
    });
  }
}

(你可以重构它以使用更好的循环条件,但你明白了)。

【讨论】:

  • 这很好用,非常感谢@Bergi!
【解决方案2】:

  await this.isTimestampReached(action.timestamp).then(() => {

然后不会被执行,因为你等待

使用下面的

const res =   await this.isTimestampReached(action.timestamp)

  this.videoPlayerRef.setState({
              paused: false,
            });
            console.log('setPlay');

或删除等待

 this.isTimestampReached(action.timestamp).then(() => {
            this.videoPlayerRef.setState({
              paused: false,
            });
            console.log('setPlay');
          });

【讨论】:

  • 如果我不等待,我将退出 switch 和 for loop 继续
  • 使用await并不意味着then不起作用。
猜你喜欢
  • 2023-03-31
  • 2017-06-21
  • 2018-02-06
  • 2018-01-24
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
相关资源
最近更新 更多