Home > Software design >  Why does an await sleep exits a for loop early?
Why does an await sleep exits a for loop early?

Time:01-07

I try to make a fade in & out effect for a music application when I click the next/previous button; I have this sleep function:

const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));

the function when the button is pushed:

function nextSong() {
  songIndex  ;
  if (songIndex > songs.length - 1) {
    songIndex = 0;
  }
  fadeOut(audio);
  loadSong(songs[songIndex]);
  playSong();
  fadeIn(audio);
}

and the fading functions

async function fadeOut(soundtrack){

    for (var i = 1.0; i > 0; i-= 0.01)
    {
        console.log(i);
        console.log(soundtrack.volume);
        soundtrack.volume = i;
        await sleep(2000);
    }
}

async function fadeIn(soundtrack){

    for (var i = 0; i <= 1; i = 0.01)
    {
        console.log(i);
        console.log(soundtrack.volume);
        soundtrack.volume = i;
        await sleep(100);
    }
}

The problem is fadeOut doesn't work at all, it goes in the for loop for 1 iteration and then exists. Meanwhile, fadeIn works perfectly. I just can't understand. Btw this is my first javascript hobby project.

CodePudding user response:

It is normal that a function returns when it gets to an await. It returns a promise. You must make sure that the caller also awaits the resolution of that promise, which will only resolve when the first function finishes all its tasks.

So:

async function nextSong() {
//^^^^
  songIndex = (songIndex   1) % songs.length;
  await fadeOut(audio);
//^^^^^
  await loadSong(songs[songIndex]);
  await playSong();
  await fadeIn(audio);
}

I am assuming here that loadSong and playSong also return promises, and so these calls also need the await operator.

CodePudding user response:

It looks like the issue might be coming from your nextSong function. You are calling multiple async functions, which are each running independently of each other. You want fadeOut to complete before loading/playing the next song.

There's two solutions to this. The first one would be to use .then to load the next song after fading out the current song:

function nextSong() {
  songIndex  ;
  if (songIndex > songs.length - 1) {
    songIndex = 0;
  }

  fadeOut(audio).then(() => {
    loadSong(songs[songIndex]);
    playSong();
    fadeIn(audio);
  });
}

Or, alternatively, you can make the function async and await the fadeOut function call:

async function nextSong() {
  songIndex  ;
  if (songIndex > songs.length - 1) {
    songIndex = 0;
  }

  await fadeOut(audio);
  loadSong(songs[songIndex]);
  playSong();
  fadeIn(audio);
}
  •  Tags:  
  • Related