Timing in JS - multiple setIntervals running at once and starting at the same time?
Asked Answered
C

6

31

Let's say I have a function:

myFunc = function(number) {
  console.log("Booyah! "+number);
}

And I want it to run on a set interval. Sounds like I should use setInterval, huh!

But what if I want to run multiple intervals of the same function, all starting at the exact same time?

setInterval(function(){
  myFunc(1);
}, 500);

setInterval(function(){
  myFunc(2);
}, 1000);

setInterval(function(){
  myFunc(3);
}, 2000);

So that the first runs exactly twice in the time it takes the second to run once, and the same between the second and third.

How do you make sure that they all start at the same time so that they are in sync?

Clockwork answered 4/12, 2013 at 2:59 Comment(2)
read ejohn.org/blog/how-javascript-timers-workRincon
javascript follows a single threaded execution pattern so at any given time there can be one active script getting executed.... so even though the timers set activated it gets queued till the active scripts gets finishedRincon
S
39

Good question, but in JS you can't. To have multiple functions in the same program execute at the same time you need multi-threading and some deep timing and thread handling skills. JS is single threaded. setInterval doesn't acutally run the function after the delay, rather after the delay it adds the function to the event stack to be run as soon as the processor can get to it. If the proc is busy with another operation, it will take longer than the delay period to actually run. Multiple intervals/timeouts are all adding calls to the same event stack, so they run in turn as the proc is available.

Shelves answered 4/12, 2013 at 3:4 Comment(0)
P
9
function Timer(funct, delayMs, times)
{
  if(times==undefined)
  {
    times=-1;
  }
  if(delayMs==undefined)
  {
    delayMs=10;
  }
  this.funct=funct;
  var times=times;
  var timesCount=0;
  var ticks = (delayMs/10)|0;
  var count=0;
  Timer.instances.push(this);

  this.tick = function()
  {
    if(count>=ticks)
    {
      this.funct();
      count=0;
      if(times>-1)
      {
        timesCount++;
        if(timesCount>=times)
        {
          this.stop();
        }
      }
    }
    count++; 
  };

  this.stop=function()
  {
    var index = Timer.instances.indexOf(this);
    Timer.instances.splice(index, 1);
  };
}

Timer.instances=[];

Timer.ontick=function()
{
  for(var i in Timer.instances)
  {
    Timer.instances[i].tick();
  }
};

window.setInterval(Timer.ontick, 10);

And to use it:

function onTick()
{
  window.alert('test');
}
function onTick2()
{
  window.alert('test2');
}
var timer = new Timer(onTick, 2000,-1);
var timer = new Timer(onTick2, 16000,-1);

For a finite number of ticks, change the last parameter to a positive integer for number. I used -1 to indicate continuous running.

Ignore anyone who tells you that you can't. You can make it do just about any thing you like!

Pharmacist answered 20/10, 2015 at 13:5 Comment(1)
This is an extremely useful piece of code. Also, it would be better if you replace the this.funct(); with eval(this.funct);. This way we can easily add function parameters. NOTE : Due to this change the functions have to be entered as Strings along with the ().Alexandrite
M
3

JavaScript is single threaded. You can use html5 web worker or try using setTimeout recursively. Create multiple functions following this example:

var interval = setTimeout(appendDateToBody, 5000);

function appendDateToBody() {
    document.body.appendChild(
        document.createTextNode(new Date() + " "));
    interval = setTimeout(appendDateToBody, 5000);
}

Read this article:

http://weblogs.asp.net/bleroy/archive/2009/05/14/setinterval-is-moderately-evil.aspx

Milky answered 4/12, 2013 at 4:22 Comment(0)
H
3

You can make something like this.

arr = Array();
arr[0] = "hi";
arr[1] = "bye";
setTimer0 = setInterval(function(id){
  console.log(arr[id])
},1000,(0));

setTimer1 = setInterval(function(id){
  console.log(arr[id]);
},500,(1));

Hope it helps!

Hippie answered 15/10, 2016 at 16:57 Comment(2)
This question was posted and answered 2 years ago. Please explain why this answer is betterExeunt
I had the same problem and this work's perfectly for me. Its from the book "Secrets of the JavaScript Ninja" By John Resig.Hippie
L
2

You can use multiples of ticks inside functions, in the example below you can run one function every 0.1 sec, and another every 1 sec. Obviously, the timing will go wrong if functions require longer times than the intervals you set. You might need to experiment with the values to make them work or tolerate the incorrect timing.

Set a variable to handle tick multiples

let tickDivider = -1

Increase the value of tick variable inside the faster function

const fastFunc = ()=> {
    tickDivider += 1
    console.log('fastFunciton')
    }

Use a condition to on running the slower function

const slowFunc = ()=> {
            if (!(tickDivider % 10)){
                console.log('slowFunction')
            }
}

Call both functions in a single one. The order is not important unless you set tickDivider to 0 (of any multiple of 10)

const updateAllFuncs = () => {
    fastFunc()
    slowFunc()
}

Set the interval to the frequency of the faster function

setInterval(updateAllFuncs, 100)
Lysozyme answered 17/6, 2020 at 17:19 Comment(0)
E
0

What I'm doing here is adding a speed attribute to the HTML elements. These speeds are passed as a parameter to setCounter(). I did this mainly to make the code easier to test and play with.

The function setCounter() is invoked inside a loop for every HTML element with class counter. This function sets a new setInterval in every execution.

The intervals seem to be working in sync.

const elements = document.querySelectorAll('.counter')

elements.forEach((el, i) => {
  let speed = Number(elements[i].getAttribute('speed'))
  setCounter(el, speed, 5000)
})

function setCounter(element, speed, elapse){
  let count = 0
  setInterval(() => {
    count = (count >= elapse) ? elapse : count + speed
    if(count === elapse) clearInterval()
    element.innerHTML = count
  }, 1)
}
Same Speeds
<p class="counter" speed='10'></p>
<p class="counter" speed='10'></p>

Different Speeds
<p class="counter" speed='3'></p>
<p class="counter" speed='5'></p>
Eleanore answered 19/4, 2022 at 10:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.