15

i am using NodeJs and need call a infinite function, but i dont know what is the best for a optimal performance.

recursive function

function test(){
//my code
test();
}

setInterval

setInterval(function(){
//my code
},60);

setTimeout

function test(){
//my code
setTimeout(test,60);
}

I want the best performance without collapse the server. My code have several arithmetic operations.

appreciate any suggestions to optimize the javascript performance.

J261
  • 642
  • 2
  • 6
  • 21

8 Answers8

36

Be carefull.. your first code would block JavaScript event loop.

Basically in JS is something like list of functions which should be processed. When you call setTimeout, setInterval or process.nextTick you will add given function to this list and when the right times comes, it will be processed..

Your code in the first case would never stop so it would never let another functions in the event list to be processed.

Second and third case is good.. with one little difference.

If your function takes to process for example 10ms and interval will be yours 60ms..

  • function with setInterval will be processed in times: 0-10, 60-70, 120-130, ... (so it has only 50ms delay between calls)
  • But with setTimeout it will be:
    • if you call func first: 0-10, 70-80, 140-150, 210-220, ...
    • if you call setTimeout first: 60-70, 130-140, 200-210, ...

So the difference is delay between starts of your function which can be important in some interval based systems, like games, auctions, stock market.. etc..

Good luck with your recursion :-)

Jan Jůna
  • 4,965
  • 3
  • 21
  • 27
  • 1
    This is the most complete and correct answer and should be accepted as an answer imo. Thanks! – Alex Yaroshevich Apr 04 '16 at 18:42
  • 2
    I see, you are talking about cca 10ms to perform execution within function. But also notable diffference is: the first example (setInterval) will be executed not immidiately, but after 60 ms. The second example (setTimeout) will be executed immidiately and then each 60 ms, upon invoking function test(). – Dalibor Jan 14 '19 at 08:17
13

As already mentioned, endless recursive functions lead to a stack overflow. Time triggered callbacks will be executed in an own context with a clear stack.

setInterval is useful for more accurate periodic calls over recursive setTimeout, however, there is a drawback: The callback will be triggered even if an uncaught exception was thrown. This usually produces a several bytes long log entry every 60 milliseconds, 1'440'000 entries per day. Furthermore a setInterval callback with heavy load could end up in an unresponsive script or even hole system.

Recursive setTimeout immediate before return from function will not be executed if any exception hasn't been caught. It will guarantee a time frame for other tasks after return from the callback function independent of the function's execution time.

Pinke Helga
  • 6,378
  • 2
  • 22
  • 42
7

Not sure what you're trying to accomplish, but here's a "safe" way to use recursion... https://stackoverflow.com/questions/24208676/how-to-use-recursion-in-javascript/24208677

/*
this will obviously crash... and all recursion is at risk of running out of call stack and breaking your page...

function recursion(c){
    c = c || 0;
    console.log(c++);
    recursion(c);
}
recursion();

*/

// add a setTimeout to reset the call stack and it will run "forever" without breaking your page!
// use chrome's heap snapshot tool to prove it to yourself.  :)

function recursion(c){
    setTimeout(function(c){
        c = c || 0;
        console.log(c++);
        recursion(c);
    },0,c);
}

recursion();

// another approach is to use event handlers, but that ultimately uses more code and more resources
Community
  • 1
  • 1
chad steele
  • 828
  • 9
  • 13
6

Recursive setTimeout guarantees a delay between the executions, setInterval – does not.

Let’s compare two code fragments. The first one uses setInterval:

let i = 1;
setInterval(function() {
  func(i);
}, 100);

The second one uses recursive setTimeout:

let i = 1;
setTimeout(function run() {
  func(i);
  setTimeout(run, 100);
}, 100);

For setInterval the internal scheduler will run func(i) every 100ms.

The real delay between func calls for setInterval is less than in the code!

That’s normal, because the time taken by func's execution “consumes” a part of the interval.

It is possible that func's execution turns out to be longer than we expected and takes more than 100ms.

In this case the engine waits for func to complete, then checks the scheduler and if the time is up, runs it again immediately.

In the edge case, if the function always executes longer than delay ms, then the calls will happen without a pause at all.

The recursive setTimeout guarantees the fixed delay (here 100ms).

solanki...
  • 4,982
  • 2
  • 27
  • 29
4

Assuming the "perfomance delay" described by Jan Juna, I have tried this simple script to check if there are any differences in terms of throughput:

Interval:

const max = 50;
const timer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 100, 150, 200, 250, 300, 400, 500];

function crono(timer) {
  return new Promise(resolve => {
    const exit = [];
    let i = 0
    setInterval(() => i++, timer);

    setInterval(() => {
      exit.push(i);
      i = 0;
      if (exit.length === max) {
        const sum = exit.reduce((a, b) => (a + b), 0);
        const avg = sum / exit.length;
        console.log(`${timer} = ${avg}`);
        resolve(avg)
      }
    }, 1000);
  });
}

Promise.all(timer.map(crono)).then(process.exit);

Timeout:

const max = 50;
const timer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 100, 150, 200, 250, 300, 400, 500];

function crono(timer) {
  return new Promise(resolve => {
    const exit = [];
    let i = 0

    const redo = () => {
      i++
      setTimeout(redo, timer);
    }

    setInterval(() => {
      exit.push(i);
      i = 0;
      if (exit.length === max) {
        const sum = exit.reduce((a, b) => (a + b), 0);
        const avg = sum / exit.length;
        console.log(`${timer} = ${avg}`);
        resolve(x)
      }
    }, 1000);

    redo();
  });
}

Promise.all(timer.map(crono)).then(process.exit);

And this is the output vith nodejs 8.11: that shows no difference in terms of throughput:

results

Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73
0

The recursive function cause a stack overflow. That's not what you want.

The setInterval and setTimeout ways you have shown are identical, except that setInterval is more clear.

I'd recommend setInterval. (After all, that is what it's for.)

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • you are right with the recursive function, it is descarted. But what about setinterval over call? – J261 Apr 20 '14 at 03:40
  • @Vorge, what is "descarted" and what is "call"? – Paul Draper Apr 20 '14 at 14:14
  • sorry, "discarded" "recursive function". after doing some tests, I have come to the conclusion that the best is the setTimeout. this way we prevent any overcall. – J261 Apr 20 '14 at 22:24
0

recursive function : Endless recursive functions lead to a stack overflow.

setTimeout code will always have at least a 60ms delay after the previous callback execution (it may end up being more, but never less)

setInterval will attempt to execute a callback every 60ms regardless of when the last callback was executed.

ashishyadaveee11
  • 1,021
  • 15
  • 17
-7

//use setInterval function

setInterval(function(){Property=value;},1000);

1000ms=1second; property like style.width etc;

  • 4
    Welcome to Stack Overflow! This question is about Node.js, a server-side technology (not in the browser). If you believe that `setInterval()` is the "best for ... optimal performance" (as the question asks), try to explain *why* it performs better than the other options. Enjoy your time on the site! – RJHunter May 27 '15 at 10:47