1

I am currently trying to get a repeating sound effect, which is getting slower over time with setTimeout() in sync with an animation. As soon as I get it in sync it will work and stay in sync for the time I am working on the program. But now when I was away for about 1 1/2 hours and run the program again exactly as I left it, the sound is no longer in sync with the animation. The same thing happend to me with the same program yesterday when I was away for some time and overnight.

So I was thinking that setTimeout() is somehow working with the current time and will work differently at different times. Can someone confirm this?

Here is my code for reference. The timeout function:

const timeoutRollSound = (time = 0, index = 0) => {
  setTimeout(() => {
      const audioClick = new Audio(
        "foo/bar.wav"
      );
      audioClick.play();
      index++;
      timeoutRollSound(0.05 * Math.pow(index, 2) + 3 * index - 50, index)
    }, time);
};

The animation:

$(".itemToAnimate").animate(
  { right: endpoint },
    {
      duration: 10000,
      easing: "easeOutQuint",
    }
);
IngoH
  • 159
  • 7
  • 3
    setTimeout isn't realtime-accurate. – Kevin B Dec 08 '21 at 22:27
  • Okay but it seems like it is accurate for a specific time frame and then suddenly gets out of sync. But when it is out of sync, it behaves like this for another specific time frame. What is the reason for this? And is there an alternative? – IngoH Dec 08 '21 at 22:35
  • 2
    Put simply, setTimeout adds a callback to the callback queue after a certain interval. there's no guarentee that the event loop will run that callback immediately, it could be delayed anywhere from 1ms to 10ms, or even more, depending on what other actions are occuring on the page. To keep things in sync, they should be occuring from within the same callback on the same interval. – Kevin B Dec 08 '21 at 22:38

2 Answers2

1

This reminds me of an issue I was having with another JS library and could be related. If you put the tab in browser to the background, the execution will be suspended. From what I'm getting from your code, you rely on the fact that the recursion setTimeout will run constantly which could be the source of your issues.

This could be the issue you are having, take a look: Chrome: timeouts/interval suspended in background tabs?

ph0enix
  • 763
  • 2
  • 8
  • 23
1

I had this issue in Java years ago. Here's what's going on.

When you set a timeout (like you are doing) you are actually saying "I don't want this function to execute before X milliseconds". So the timeout function may be ready to run, but JavaScript or the browser might be doing something else.

setInterval might work better. But the other thing you can do is include the difference between when the code was eligible to be run and the time it was actually run at, like:

  setTimeout(() => {
      const audioClick = new Audio(
        "foo/bar.wav"
      );
      audioClick.play();
      index++;
      timeoutRollSound(0.05 * Math.pow(index, 2) + 3 * index - 50, index)
      timeoutRollSound.last = Date.now();

    },  time - ((Date.now - timeoutRollSound.last) ); 
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • To get the time difference between the time the code ran and when it was eligible to run seems to work for me. Thanks for your answer! – IngoH Dec 08 '21 at 23:25