Resolve a promise inside a promise

Viewed 172

I'm stuck in a problem, i have a react-native app where i have a set of actions in order to display a video (i record those action before).

I have a for loop on all action and need to wait for the video to reach a certain timestamp in order to trigger the action. For that i use a switch to identify all my actions, and inside wait for a promise in order to trigger the action at the good timestamp.

Here is my code :

  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`);
      }
    }
  };

and the log : enter image description here

We can see that i'm staying inside the for loop and the switch because i don't get the console.log('pause outside loop'); . But as you can see i don't get the console.log('set Pause'); too. So this means my Promise did not resolve.

I think the problem is launching a promise inside a promise because for the first case (play) it work directly. But i don't see how i can solve this issue.

Thanks in advance from the community

PS: i've put only the javascript tag because i don't think this has something to do with react nor react-native.

2 Answers

This means my Promise did not resolve. I think the problem is launching a promise inside a promise.

Indeed. In the executor callback of new Promise, you call only setTimeout but never resolve() or reject(). The isTimestampReached call 100ms later does create and return its own promise, the original "outer" promise is never resolved. You could work around that by doing

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

but with async/await it is much easier to do polling:

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);
    });
  }
}

(You can refactor that to use a nicer loop condition, but you get the idea).


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

then will not get executed , as you await

use the below

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

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

or remove await

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

Related