Jorge
Jorge

Reputation: 18257

Execute the setInterval function without delay the first time

It's there a way to configure the setInterval method of javascript to execute the method immediately and then executes with the timer

Upvotes: 564

Views: 322043

Answers (19)

BaSsGaz
BaSsGaz

Reputation: 794

This is what I always use for this case, 100% of the time, it works every time.

function startInterval(callback, timeout, ...args) {
  const intervalID = setInterval(callback, timeout, ...args);
  setTimeout(callback, ...args);
  return intervalID;
}

Simple and straightforward. Just switch your setInterval() with startInterval().

The problem with many other approaches is that clearInterval() cannot be called within your callback, as it isn't defined until after setInterval() has been called. The setTimeout() approach here allows us to return the intervalID right away, allowing the callback to access it immediately.

Upvotes: 0

David Callanan
David Callanan

Reputation: 5800

With ES2017, it may be preferable to avoid setInterval altogether.

The following solution has a much cleaner execution flow, prevents issues if the function takes longer than the desired time to complete, and allows for asynchronous operations.

const timeout = (delayMs) => new Promise((res, _rej) => setTimeout(res, delayMs));

const DELAY = 1_000;

(async () => {
  while (true) {
    let start_time = Date.now();

    // insert code here...

    let end_time = Date.now();
    await timeout(DELAY - (end_time - start_time));
  }
})();

Upvotes: 0

usertest
usertest

Reputation: 2272

For Those using React, here is how I solve this problem:

const intervalRef = useRef(0);

useEffect(() => {
    if (condition is true){
        if (intervalRef.current === 0) {
            callMyFunction();
        }
        const interval = setInterval(() => {
            callMyFunction();
        }, 5_000);
        intervalRef.current = interval;
    } else {
        clearInterval(intervalRef.current);
    }
}, [deps]);

Upvotes: 1

1337ingDisorder
1337ingDisorder

Reputation: 887

This example builds on @Alnitak's answer, but uses await Promise for finer granularity of control within the loop cycle.

Compare examples:

let stillGoing = true;

(function foo() {
    console.log('The quick brown fox did its thing');
    if (stillGoing) setTimeout(foo, 5000);
})();

foo();

In the above example we call foo() and then it calls itself every 5 seconds.

But if, at some point in the future, we set stillGoing to false in order to stop the loop, we'll still get an extra log line even after we've issued the stop order. This is because at any given time, before we set stillGoing to false the current iteration will have already created a timeout to call the next iteration.

If we instead use await Promise as the delay mechanism then we have an opportunity to stop the loop before calling the next iteration:

let stillGoing = true;

(async function foo() {
    console.log('The quick brown fox did its thing');
    await new Promise(resolve => setTimeout(resolve, 5000));
    if (stillGoing) foo();
})();

foo();

In the second example we start by setting a 5000ms delay, after which we check the stillGoing value and decide whether calling another recursion is appropriate.

So if we set stillGoing to false at any point, there won't be that one extra log line printed after we set the value.

The caveat is this requires the function to be async, which may or may not be an option for a given use.

Upvotes: 1

Guntram
Guntram

Reputation: 980

If you can use RxJS, there is something called timer():

import { Subscription, timer } from 'rxjs';

const INITIAL_DELAY = 1;
const INTERVAL_DELAY = 10000;
const timerSubscription = timer(INITIAL_DELAY, INTERVAL_DELAY)
  .subscribe(() => {
    this.updateSomething();
  });

// when destroying
timerSubscription.unsubscribe();

Upvotes: 1

reo_yamanaka
reo_yamanaka

Reputation: 31

You can set a very small initial delay-time (e.g. 100) and set it to your desired delay-time within the function:

var delay = 100;

function foo() {
  console.log("Change initial delay-time to what you want.");
  delay = 12000;
  setTimeout(foo, delay);
}

Upvotes: 3

Alnitak
Alnitak

Reputation: 339975

It's simplest to just call the function yourself directly the first time:

foo();
setInterval(foo, delay);

However there are good reasons to avoid setInterval - in particular in some circumstances a whole load of setInterval events can arrive immediately after each other without any delay. Another reason is that if you want to stop the loop you have to explicitly call clearInterval which means you have to remember the handle returned from the original setInterval call.

So an alternative method is to have foo trigger itself for subsequent calls using setTimeout instead:

function foo() {
   // do stuff
   // ...

   // and schedule a repeat
   setTimeout(foo, delay);
}

// start the cycle
foo();

This guarantees that there is at least an interval of delay between calls. It also makes it easier to cancel the loop if required - you just don't call setTimeout when your loop termination condition is reached.

Better yet, you can wrap that all up in an immediately invoked function expression which creates the function, which then calls itself again as above, and automatically starts the loop:

(function foo() {
    ...
    setTimeout(foo, delay);
})();

which defines the function and starts the cycle all in one go.

Upvotes: 803

codermapuche
codermapuche

Reputation: 472

// YCombinator
function anonymous(fnc) {
  return function() {
    fnc.apply(fnc, arguments);
    return fnc;
  }
}

// Invoking the first time:
setInterval(anonymous(function() {
  console.log("bar");
})(), 4000);

// Not invoking the first time:
setInterval(anonymous(function() {
  console.log("foo");
}), 4000);
// Or simple:
setInterval(function() {
  console.log("baz");
}, 4000);

Ok this is so complex, so, let me put it more simple:

function hello(status ) {    
  console.log('world', ++status.count);
  
  return status;
}

setInterval(hello, 5 * 1000, hello({ count: 0 }));

Upvotes: 0

For someone needs to bring the outer this inside as if it's an arrow function.

(function f() {
    this.emit("...");
    setTimeout(f.bind(this), 1000);
}).bind(this)();

If the above producing garbage bothers you, you can make a closure instead.

(that => {
    (function f() {
        that.emit("...");
        setTimeout(f, 1000);
    })();
})(this);

Or maybe consider using the @autobind decorator depending on your code.

Upvotes: 3

Polyducks
Polyducks

Reputation: 213

Here's a simple version for novices without all the messing around. It just declares the function, calls it, then starts the interval. That's it.

//Declare your function here
function My_Function(){
  console.log("foo");
}    

//Call the function first
My_Function();

//Set the interval
var interval = window.setInterval( My_Function, 500 );

Upvotes: 5

Mahn
Mahn

Reputation: 16605

Here's a wrapper to pretty-fy it if you need it:

(function() {
    var originalSetInterval = window.setInterval;

    window.setInterval = function(fn, delay, runImmediately) {
        if(runImmediately) fn();
        return originalSetInterval(fn, delay);
    };
})();

Set the third argument of setInterval to true and it'll run for the first time immediately after calling setInterval:

setInterval(function() { console.log("hello world"); }, 5000, true);

Or omit the third argument and it will retain its original behaviour:

setInterval(function() { console.log("hello world"); }, 5000);

Some browsers support additional arguments for setInterval which this wrapper doesn't take into account; I think these are rarely used, but keep that in mind if you do need them.

Upvotes: 7

jimm101
jimm101

Reputation: 998

There's a convenient npm package called firstInterval (full disclosure, it's mine).

Many of the examples here don't include parameter handling, and changing default behaviors of setInterval in any large project is evil. From the docs:

This pattern

setInterval(callback, 1000, p1, p2);
callback(p1, p2);

is identical to

firstInterval(callback, 1000, p1, p2);

If you're old school in the browser and don't want the dependency, it's an easy cut-and-paste from the code.

Upvotes: 3

Jayant Varshney
Jayant Varshney

Reputation: 1825

I will suggest calling the functions in the following sequence

var _timer = setInterval(foo, delay, params);
foo(params)

You can also pass the _timer to the foo, if you want to clearInterval(_timer) on a certain condition

var _timer = setInterval(function() { foo(_timer, params) }, delay);
foo(_timer, params);

Upvotes: 3

Jens Wirth
Jens Wirth

Reputation: 17460

I stumbled upon this question due to the same problem but none of the answers helps if you need to behave exactly like setInterval() but with the only difference that the function is called immediately at the beginning.

Here is my solution to this problem:

function setIntervalImmediately(func, interval) {
  func();
  return setInterval(func, interval);
}

The advantage of this solution:

  • existing code using setInterval can easily be adapted by substitution
  • works in strict mode
  • it works with existing named functions and closures
  • you can still use the return value and pass it to clearInterval() later

Example:

// create 1 second interval with immediate execution
var myInterval = setIntervalImmediately( _ => {
        console.log('hello');
    }, 1000);

// clear interval after 4.5 seconds
setTimeout( _ => {
        clearInterval(myInterval);
    }, 4500);

To be cheeky, if you really need to use setInterval then you could also replace the original setInterval. Hence, no change of code required when adding this before your existing code:

var setIntervalOrig = setInterval;

setInterval = function(func, interval) {
    func();
    return setIntervalOrig(func, interval);
}

Still, all advantages as listed above apply here but no substitution is necessary.

Upvotes: 47

user4989618
user4989618

Reputation:

To solve this problem , I run the function a first time after the page has loaded.

function foo(){ ... }

window.onload = function() {
   foo();
};

window.setInterval(function()
{
    foo(); 
}, 5000);

Upvotes: 1

Hertzel Armengol
Hertzel Armengol

Reputation: 64

actually the quickest is to do

interval = setInterval(myFunction(),45000)

this will call myfunction, and then will do it agaian every 45 seconds which is different than doing

interval = setInterval(myfunction, 45000)

which won't call it, but schedule it only

Upvotes: -10

Xe-Xe
Xe-Xe

Reputation: 47

There's a problem with immediate asynchronous call of your function, because standard setTimeout/setInterval has a minimal timeout about several milliseconds even if you directly set it to 0. It caused by a browser specific work.

An example of code with a REAL zero delay wich works in Chrome, Safari, Opera

function setZeroTimeout(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
channel.port2.postMessage('');
}

You can find more information here

And after the first manual call you can create an interval with your function.

Upvotes: -2

user113716
user113716

Reputation: 322572

You could wrap setInterval() in a function that provides that behavior:

function instantGratification( fn, delay ) {
    fn();
    setInterval( fn, delay );
}

...then use it like this:

instantGratification( function() {
    console.log( 'invoked' );
}, 3000);

Upvotes: 11

chjj
chjj

Reputation: 14602

I'm not sure if I'm understanding you correctly, but you could easily do something like this:

setInterval(function hello() {
  console.log('world');
  return hello;
}(), 5000);

There's obviously any number of ways of doing this, but that's the most concise way I can think of.

Upvotes: 300

Related Questions