Javascript, setTimeout loops?

javascript settimeout loop until condition is true
javascript settimeout for loop delay
javascript setinterval
javascript setinterval loop
javascript infinite loop with delay
javascript wait
settimeout in while loop
setinterval not working

So I am working on a music program that requires multiple javascript elements to be in sync with another. I've been using setInterval which works really well initially however over time the elements gradually become out of sync which with a music program is bad.

I've read online that setTimeout is more accurate, and you can have setTimeout loops somehow however I have not found a generic version that illustrates how this is possible. Could someone just show me a basic example of using setTimeout to loop something indefinitely.

Thank you. Alternatively, if there is a way to achieve more synchronous results with setInterval or even another function, please let me know.

EDIT:

Basically I have some functions like such:

//drums
setInterval(function {
//code for the drums playing goes here
},8000);

//chords
setInterval(function {
//code for the chords playing goes here
},1000);

//bass
setInterval(function {
//code for the bass playing goes here
},500);

It works super well initially but over the course of about a minute, the sounds become noticeably out of sync as I've read happens with setInterval, I've read that setTimeout can be more consistently accurate.

You can create a setTimeout loop using recursion:

function timeout() {
    setTimeout(function () {
        // Do Something Here
        // Then recall the parent function to
        // create a recursive loop.
        timeout();
    }, 1000);
}

The problem with setInterval() and setTimeout() is that there is no guarantee your code will run in the specified time. By using setTimeout() and calling it recursively, you're ensuring that all previous operations inside the timeout are complete before the next iteration of the code begins.

Be careful with setTimeout in loops (Example), A protip by zinkkrysty about js, arguments, javascript, settimeout, and context. Understanding setTimeout in JavaScript setTimeout is used to fire a piece of code after the specified timers expires. Here is an example code to demonstrate setTimeout. As shown in the above piece of code, the callback function is executed after the specified time interval expires.

Only to supplement. If you need to pass a variable and iterate it, you can do just like so:

function start(counter){
  if(counter < 10){
    setTimeout(function(){
      counter++;
      console.log(counter);
      start(counter);
    }, 1000);
  }
}
start(0);

Output:

1
2
3
...
9
10

One line per second.

Watch Out When Using SetTimeout() in For Loop #JS, setTimeout function in JavaScript usually takes a callback function as an argument. A callback function is a function that is executed after  Using setTimeout in the example loop will not behave as expected, if you expect that there will be a one second interval between each task. What happens instead is the whole loop is executed in under a millisecond, and each of the 5 tasks is scheduled to be placed on the synchronous JS event queue one second later.

Given that neither time is going to be very accurate, one way to use setTimeout to be a little more accurate is to calculate how long the delay was since the last iteration, and then adjust the next iteration as appropriate. For example:

var myDelay = 1000;
var thisDelay = 1000;
var start = Date.now();

function startTimer() {    
    setTimeout(function() {
        // your code here...
        // calculate the actual number of ms since last time
        var actual = Date.now() - start;
        // subtract any extra ms from the delay for the next cycle
        thisDelay = myDelay - (actual - myDelay);
        start = Date.now();
        // start the timer again
        startTimer();
    }, thisDelay);
}

So the first time it'll wait (at least) 1000 ms, when your code gets executed, it might be a little late, say 1046 ms, so we subtract 46 ms from our delay for the next cycle and the next delay will be only 954 ms. This won't stop the timer from firing late (that's to be expected), but helps you to stop the delays from pilling up. (Note: you might want to check for thisDelay < 0 which means the delay was more than double your target delay and you missed a cycle - up to you how you want to handle that case).

Of course, this probably won't help you keep several timers in sync, in which case you might want to figure out how to control them all with the same timer.

So looking at your code, all your delays are a multiple of 500, so you could do something like this:

var myDelay = 500;
var thisDelay = 500;
var start = Date.now();
var beatCount = 0;

function startTimer() {    
    setTimeout(function() {
        beatCount++;
        // your code here...
        //code for the bass playing goes here  

        if (count%2 === 0) {
            //code for the chords playing goes here (every 1000 ms)
        }

        if (count%16) {
            //code for the drums playing goes here (every 8000 ms)
        }

        // calculate the actual number of ms since last time
        var actual = Date.now() - start;
        // subtract any extra ms from the delay for the next cycle
        thisDelay = myDelay - (actual - myDelay);
        start = Date.now();
        // start the timer again
        startTimer();
    }, thisDelay);
}

Thrown for a loop: understanding for loops and timeouts in JavaScript, for(var i = 1; i < 6; i++) { setTimeout(function() { console.log(i); },1000); } console.​log('The loop is done!');. Take some time to think about what  The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds. Tip: 1000 ms = 1 second. Tip: The function is only executed once. If you need to repeat execution, use the setInterval() method. Tip: Use the clearTimeout() method to prevent the function from running.

The best way to deal with audio timing is with the Web Audio Api, it has a separate clock that is accurate regardless of what is happening in the main thread. There is a great explanation, examples, etc from Chris Wilson here:

http://www.html5rocks.com/en/tutorials/audio/scheduling/

Have a look around this site for more Web Audio API, it was developed to do exactly what you are after.

Scheduling: setTimeout and setInterval, setTimeout allows us to run a function once after the interval of time. that we'll discuss in the chapter Event loop: microtasks and macrotasks. The setTimeout above schedules the next call right at the end of the current one (*).. The nested setTimeout is a more flexible method than setInterval.This way the next call may be scheduled differently, depending on the results of the current one.

Use setInterval()

setInterval(function(){
 alert("Hello"); 
}, 3000);

The above will execute alert("Hello"); every 3 seconds.

JavaScript Timing Events, The two key methods to use with JavaScript are: setTimeout(function, milliseconds ) Executes a function, after waiting a specified number of milliseconds. setInterval(function, milliseconds ) Same as setTimeout(), but repeats the execution of the function continuously. The two key methods to use with JavaScript are: setTimeout(function, milliseconds) Executes a function, after waiting a specified number of milliseconds. setInterval(function, milliseconds)

Understanding setTimeout Inside For Loop In JavaScript, In this tutorial, you'll see some issues related to using setTimeout inside for loop and how to work around such issues. JavaScript doesn’t offer any wait command to add a delay to the loops but we can do so using setTimeout method. This method executes a function, after waiting a specified number of milliseconds. This method executes a function, after waiting a specified number of milliseconds.

How to add a delay in a JavaScript loop?, JavaScript doesn't offer any wait command to add a delay to the loops but we can do so using setTimeout method. This method executes a function, after waiting  How JavaScript setTimeout() works. JavaScript is single-threaded therefore it can only do one task at a time. It means that it can only carry a single task a given time. Besides the JavaScript engine, the web browser has other components such as Event Loop, Call Stack, and Web API.

Window clearTimeout() Method, () method calls a function or evaluates an expression after a specified number of milliseconds. Tip: 1000 ms = 1 second. Tip: The function is only executed once. If you need to repeat execution, use the setInterval() method. If you execute code like setTimeout(fn, 0) but then immediately after run a loop that counts from 1 to 10 billion, your callback will be executed after a few seconds. In the following example, the browser will wait two seconds before executing the anonymous function, then will display the alert message ( see it running live , and see the source

Comments
  • Why don't you post some code showing us what you want to achieve and we can give you better answers.
  • I've read online that setTimeout is more accurate: Where did you read that? Include a link. I'm assuming it's probably a case with setTimeout you can calculate how long the delay really was a adjust the time for the next timeout.
  • What about requestAnimationFrame? You'd just have to reference the time that the audio is at each time your requestAnimationFrame callback runs.
  • Neither type of timer is really guaranteed to be precise. The milliseconds given is just a minimum wait time, but the function can still be called later. If you're trying to coordinate multiple intervals, try instead consolidating to one, controlling interval.
  • If you really want to sync music to something on-screen, you need to reference the time progress through the audio when you update the DOM. Otherwise things will get out of sync most of the time.
  • What's the difference between this method and using setInterval?
  • the issue with this approach is that if the function takes longer than 1000ms to complete, it all goes belly up. this isnt guaranteed to execute every 1000ms. setInterval is.
  • @TJC: That very much depends on exactly what you are trying to achieve. It might be more important that the previous function complete before the next iteration, or maybe not.
  • @TJC Correct, but if your previous operations are not complete before setInterval() re-executes, your variables and/or data could get out of sync really fast. If I'm ajaxing for data for example, and the server takes longer than 1 sec to respond, using setInterval() my previous data would not have finished processing before my next operation continued. With this approach, it's not guaranteed that your function will kick off every second. However, it is guaranteed that your previous data will have finished processing before the next interval kicks off.
  • @War10ck, given a music based environment, I assumed that it was not going to be used to set variables or ajax calls where order mattered.
  • +1 Neat approach. I never thought about offsetting the timeout period of the next run. That would probably get you as close to an exact measurement as you can get considering JavaScript is not multi-threaded and not guaranteed to fire at a consistent time interval.
  • This is great! I'm going to try this and let you know how it goes. My code is massive so it'll probably take a while
  • Consider: Having this code trigger on a fixed (even if corrected, as above) time-loop might actually be the wrong way to think about the problem. It could be that you should actually set each interval length to "next-time-something-is-due-to-be-played minus current-time".
  • I really wish more people would upvote this. Answers using setTimeout range from insufficient to horribly overcomplex. Using a native function seems like a much better idea. If the API doesn't serve your purpose, then I would recommend trying to find a reliable third party scheduling library.