2017-06-27 67 views
-1

实现回调(几乎)只有一个结束就可以了(所谓的)“递归”语法以前的回调后第二次的重复执行的标准方式:JS setTimeout()重复循环不比循环语法更好,以防止堆栈耗尽?

function callback_recurse(){ 
    // do something, if <condtion> break 
    setTimeout(callback_recurse, 1000); 
} 
setTimeout(callback_recurse, 1000); // first call 

为什么不使用循环语法呢? :

function callback(){ 
    // do something 
} 
function loopcallbacks(){ 
    while (<condition>) 
     setTimeout(callback, 1000); 
} 

毕竟,您将永远不会使用迭代循环语法用完堆栈空间,就像您将使用递归语法一样。

(声明:我回答我的问题)

+0

我不知道我理解为什么因为它是一个无限循环的第二个例子甚至可以考虑的选择。 – zzzzBov

+0

第一个片段不是递归的。这是伪递归,我不希望它增长调用堆栈。同样在第二个片段中,您将同步地将无数回调插入到事件循环后1000毫秒执行。 – Redu

回答

1

在里面loopcallbacks()不会表现在循环使用的setTimeout()如预期,如果预期会有一秒钟每个任务之间的间隔。假设你的程序中有5次迭代循环,而不是无限循环。 然后整个循环在毫秒之内执行,并且5个任务中的每一个都计划在一秒钟之后放置在同步JS事件队列中。他们将按顺序连续运行,但不是每个人都相隔一秒钟。如果它是一个无限循环,因为在执行任何任务之前程序将会阻塞并且堆栈会溢出。

您不必担心在callback_recurse()中使用所谓的“递归”语法来用尽堆栈空间。实际上它不是真正的递归,因为调用函数在新计划的任务运行之前返回,所以堆栈的大小不会增加。因此,使用所谓的“递归”语法永远不会耗尽堆栈空间。

下面的程序演示了这两种循环和递归语法:

首先,循环语法运行。输出格式为

([index], time from start, time from previous task). 

正如您所看到的,所有5个任务在运行循环后运行约1秒钟。 (但是,请注意,它们是按顺序连续运行的 - 它们不是异步运行的)。

其次,运行所谓的递归语法。输出格式是相同的,这次结果符合所需的行为。

function time_ms() { 
 
    var d = new Date(); 
 
    var t = d.getTime(); 
 
    return t; 
 
} 
 
function makestr(d0,dlast,d,idx){ 
 
    var s0,s1; 
 
    if (idx === 0) s0 = "*"; else s0 = (d-dlast).toString(); 
 
    s1 = (d-d0).toString() 
 
\t var s = "([" + idx.toString() + "]," + s0 + "," + s1 + "), "; 
 
    return s; 
 
} 
 

 
function run1_sub(i,is_last){ 
 
    setTimeout(function() { 
 
     d = time_ms(); 
 
     s = makestr(d0,dlast,d,i); 
 
     dlast = d; 
 
     document.getElementById("1").innerHTML += s; 
 
     // maybe mixing metaphors, but this ensures that run2 starts after run1 finishes 
 
     if (is_last) 
 
     setTimeout(run2(),0) 
 
    }, 1000); 
 
} 
 

 
function run1() { 
 
    var s = ""; 
 
    var i; 
 
    var d0 = time_ms(); 
 
    var dlast = d0; 
 
    for (i = 0; i < 5; i += 1) { 
 
    \t run1_sub(i,i==4); 
 
    } 
 
} 
 
var j = 0; 
 
var d0 = time_ms(); 
 
var dlast = d0; 
 

 
function run2() { 
 
    var s = ""; 
 
    d = time_ms(); 
 
    s = makestr(d0,dlast,d,j); 
 
    dlast = d; 
 
    document.getElementById("2").innerHTML += s; 
 
    j += 1; 
 
    if (j < 5) 
 
    setTimeout(run2, 1000); 
 
} 
 

 
run1(); // run2() is first called from insde the last callback of run1()
<div id="1"> 
 
</div> 
 
<div id="2"> 
 
</div>

+0

没有回调将永远不会运行。 * while(true)*阻塞 –

+0

@Jonasw,对于无限循环setTimeouts(),这是真的。 –