Search code examples
javascriptasync-awaitsleepaudio-player

Why does an await sleep exits a for loop early?


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.


Solution

  • 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.