简体   繁体   English

递归 function vs setInterval vs setTimeout javascript

[英]recursive function vs setInterval vs setTimeout javascript

i am using NodeJs and need call a infinite function, but i dont know what is the best for a optimal performance.我正在使用 NodeJs,需要调用无限 function,但我不知道什么是最佳性能的最佳选择。

recursive function递归 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.感谢任何优化 javascript 性能的建议。

Be carefull.. your first code would block JavaScript event loop. 小心..你的第一个代码会阻止JavaScript事件循环。

Basically in JS is something like list of functions which should be processed. 基本上在JS中就像应该处理的函数列表。 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.. 当你调用setTimeoutsetIntervalprocess.nextTick你会将给定的函数添加到这个列表中,当正确的时间到来时,它将被处理。

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.. 如果你的功能需要处理10毫秒,间隔将是你的60毫秒..

  • function with setInterval will be processed in times: 0-10, 60-70, 120-130, ... (so it has only 50ms delay between calls) 具有setInterval的函数将在以下时间内处理:0-10,60-70,120-130 ......(所以它之间的调用只有50ms延迟)
  • But with setTimeout it will be: 但是使用setTimeout它将是:
    • if you call func first: 0-10, 70-80, 140-150, 210-220, ... 如果你先调用func:0-10,70-80,140-150,210-220,......
    • if you call setTimeout first: 60-70, 130-140, 200-210, ... 如果你先调用setTimeout: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 :-) 祝你的递归好运:-)

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 . setInterval对于递归setTimeout更准确的定期调用很有用,但是,有一个缺点: 即使抛出未捕获的异常,也会触发回调 This usually produces a several bytes long log entry every 60 milliseconds, 1'440'000 entries per day. 这通常每60毫秒产生几个字节长的日志条目,每天产生1'440'000个条目。 Furthermore a setInterval callback with heavy load could end up in an unresponsive script or even hole system. 此外,负载较重的setInterval回调可能会导致无响应的脚本甚至是漏洞系统。

Recursive setTimeout immediate before return from function will not be executed if any exception hasn't been caught. 如果没有捕获到任何异常,则在从函数返回之前立即递归setTimeout 不会被执行。 It will guarantee a time frame for other tasks after return from the callback function independent of the function's execution time. 它将保证从回调函数返回后的其他任务的时间范围,而与函数的执行时间无关。

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 不知道你想要完成什么,但这是一种使用递归的“安全”方式... 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

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: 假设Jan Juna描述的“性能延迟”,我尝试了这个简单的脚本来检查吞吐量方面是否存在任何差异:

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: 这是输出vith nodejs 8.11:在吞吐量方面没有显示差异:

结果

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. 您显示的setIntervalsetTimeout方式是相同的,只是setInterval更清晰。

I'd recommend setInterval . 我推荐setInterval (After all, that is what it's for.) (毕竟,这就是它的用途。)

Recursive setTimeout guarantees a delay between the executions, setInterval – does not. 递归setTimeout保证执行之间的延迟, setInterval - 没有。

Let's compare two code fragments. 让我们比较两个代码片段。 The first one uses setInterval : 第一个使用setInterval

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

The second one uses recursive setTimeout : 第二个使用递归setTimeout

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

For setInterval the internal scheduler will run func(i) every 100ms. 对于setInterval ,内部调度程序将每100ms运行一次func(i)

The real delay between func calls for setInterval is less than in the code! func调用setInterval之间的实际延迟小于代码!

That's normal, because the time taken by func's execution “consumes” a part of the interval. 这是正常的,因为func's执行所花费的时间“消耗”了一部分间隔。

It is possible that func's execution turns out to be longer than we expected and takes more than 100ms. func's执行可能比我们预期的要长,并且需要超过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. 在这种情况下,引擎等待func完成,然后检查调度程序,如果时间到了,立即再次运行它。

In the edge case, if the function always executes longer than delay ms, then the calls will happen without a pause at all. 在边缘情况下,如果函数总是执行的时间长于delay ms,那么调用将完全没有暂停。

The recursive setTimeout guarantees the fixed delay (here 100ms). 递归setTimeout保证固定delay (此处为100ms)。

recursive function : Endless recursive functions lead to a stack overflow. recursive function :无尽的递归函数导致堆栈溢出。

setTimeout code will always have at least a 60ms delay after the previous callback execution (it may end up being more, but never less) setTimeout代码在上一次回调执行后总是会有至少 60 毫秒的延迟(最终可能会更多,但绝不会更少)

setInterval will attempt to execute a callback every 60ms regardless of when the last callback was executed. setInterval将尝试每 60 毫秒执行一次回调,无论上次回调何时执行。

//use setInterval function //使用setInterval函数

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

1000ms=1second; 1000毫秒=1秒; property like style.width etc; 像style.width等属性;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM