89

In a simple setInterval

setInterval(function() {
      // Do something every 9 seconds
}, 9000);

The first action will happen after 9 seconds (t=9s). How to force the loop to perform the first action immediately (t=0)?

I think it is due to the mechanism of setInterval to have Delay - Action - Delay - Action ... loop; instead of Action - Delay - Action - Delay ... loop.

EDIT: My function is indeed a loop as

setInterval(function(){
$('.test').each(function(idx){
    var duration = 1000;
    $(this).delay(duration*idx);
    Some stuff here
});
}, 4000);
vaisakh
  • 1,041
  • 9
  • 19
Googlebot
  • 15,159
  • 44
  • 133
  • 229

4 Answers4

181

Keep it simple. You can use a named function instead of an anonymous function; call it and set an interval for it.

function doSomething() {
    console.log("tick");
}
doSomething();
setInterval(doSomething, 9000);

Create a scope if necessary:

(function() {
    function doSomething() {
        console.log("tick");
    }
    doSomething();
    setInterval(doSomething, 9000);
})();

Finally, the following works without creating or affecting x:

setInterval(function x() {
    console.log("tick");
    return x;
}(), 9000);
Salman A
  • 262,204
  • 82
  • 430
  • 521
  • 1
    The first part of this answer will get progressively slower, as a new `setInterval` is made every loop. This could be fixed by replacing `window.setInterval` with `setTimeout`. – Jacob Birkett Jan 07 '18 at 22:57
  • I wonder how the 2nd sample would work with a lambda function? – ESP32 Jan 08 '19 at 21:54
27

Sometimes I use this pattern...

(function me() {
    // Do something every 9 seconds

    setTimeout(me, 9000);
})();

It's not quite the same, as it will wait until the do something is executed before waiting ~9 seconds to call it again. But, this is often useful so events on the event queue do not stack up needlessly (however unlikely it is some code will take 9 seconds to run :)

Note that in older IEs, the me will leak to the outside scope.

alex
  • 479,566
  • 201
  • 878
  • 984
  • *"Note that in older IEs, the me will leak to the outside scope."* And two different functions are created, at different times, with the same code. The *first* time your code runs, it's one of them; all the subsequent times it's the other one. Weird but true. – T.J. Crowder May 12 '12 at 11:54
  • I wish this worked seamlessly on all browsers. It's just so clean. Which versions of IE malfunction? – thekingoftruth Dec 13 '13 at 23:48
  • @thekingoftruth It should *work* seamlessly, it will just leak the `me` identifier in IE. From memory, it's <= IE8 that has an issue. – alex Dec 14 '13 at 07:11
  • @alex I can live with that. :) I wonder if `(var me = function(){...` would work as well. edit: ah, I see that it will not. – thekingoftruth Dec 17 '13 at 23:35
  • @thekingoftruth `var = ` is `undefined`, whereas ` = ` is `` (which is effectively equal to ``. So you can do `var me; (me = function() { … })()`. – Iso Feb 21 '14 at 14:46
  • You have a recursion loop that will add one call to the callstack every time it runs. Eventually, you will hit the maximum call stack size and your app will crash. https://developer.cdn.mozilla.net/pl/docs/Web/JavaScript/Reference/Errors/Too_much_recursion – fabien Feb 24 '20 at 11:09
  • Nice trick. But it won't be long before some messes up this code and introduce some bugs. –  Jun 05 '20 at 12:45
21

I use this sanitized version of setInterval, which does call the function immediately, and takes a time in seconds, BEFORE the function parameter so calling it with an inline function definition actually looks sensible.

function startInterval(seconds, callback) {
  callback();
  return setInterval(callback, seconds * 1000);
}
Switch386
  • 454
  • 6
  • 19
Richard
  • 1,803
  • 17
  • 17
  • If callback calls clearInterval(), it will always fail to clear the interval in the first call with this implementation. What would work is: `const id = setInterval(...); setTimeout(callback); return id;` this ensures that the intervalId is not undefined in the first call to callback – Areeb May 10 '21 at 19:09
4

Use a named function and call it and assign it to the interval.

var myFnc = function() {
    // Do something every 9 seconds
};
setInterval(myFnc, 9000);
myFnc();

The other option is to use setTimeout instead.

var myFnc = function() {
    // Do something every 9 seconds
    setTimeout(myFnc, 9000);
};
myFnc();
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • 4
    That's not a named function. It's an anonymous function assigned to a variable. The *variable* has a name, the function does not (which is fine for what you're doing, other than that some debuggers won't be able to show you a useful name in call stacks and such [others do, the latest Chrome Dev Tools and Firebug are quite smart]). – T.J. Crowder May 12 '12 at 11:46