运行setTimeout方法+传递变量的Javascript堆栈溢出

问题描述:

我知道我遇到的问题是,我只是很难找到解决办法。我想知道是否有人经历过这样的事情,他们实施了什么样的解决方案。运行setTimeout方法+传递变量的Javascript堆栈溢出

我有一个名单系统,等待维修,我想这是迟到闪烁黑色和红色修理。这个列表中有很多修复可能很晚。

这里是我的功能:

function setblink(id) { 
    var elm = document.getElementById(id); 
    if (elm.color == "red"){ 
     elm.color = "black"; 
    } 
    else{ 
     elm.color = "red"; 
    } 
    setTimeout(setblink(id),500); 
} 

我有“的ID”对于需要闪烁称为repsToBlink项目的数组。

我得到通过运行下面的代码,这使他们在递归循环运行的每个这些修复的设定眨眼的时间间隔。

for(var x in repsToBlink){ 
setTimeout(setblink(repsToBlink[x]),500); 
} 

我怎样才能得到这段代码做同样的事情,而不会导致堆栈溢出?

谢谢!

+1

如果你想用纯CSS做这个试试[this](http://jsfiddle.net/Krr7m/)。有关[MDN]的更多信息(https://developer.mozilla.org/en/CSS/CSS_animations)。您需要添加更多供应商特定的前缀才能使其适用于更多浏览器,并且不适用于旧版浏览器。 – 2012-01-16 18:21:26

+0

我不是每个元素的'setTimeout()'的忠实粉丝。使用列表,而不是:http://jsfiddle.net/HdCbt/ – 2012-01-16 18:48:32

+0

[超过最大调用堆栈大小]的Dup(http://*.com/questions/8731840/),[为什么使用括号调用setTimeout不启动新的callstack?](http://*.com/questions/8058996/)。 – outis 2012-01-16 19:19:24

您需要在setTimeout的从

setTimeout(setblink(id),500); 

更改为:

setTimeout(function() { setblink(id) },500); 

setTimeout()预期的功能,如参数传递,而你传递函数的结果。

setblink(id)立即调用该函数。由于setTimeout计划稍后执行,因此堆栈溢出是立即执行而非延迟执行的症状,因此未来的调用不会被推送到当前调用堆栈上。

由于setblink需要一个参数,因此将其包装在一个nullary匿名函数中,用于lazy evaluation

function setblink(id) { 
    var elm = document.getElementById(id); 
    if (elm.color == "red"){ 
     elm.color = "black"; 
    } 
    else{ 
     elm.color = "red"; 
    } 
    setTimeout(function() {setblink(id)},500); 
} 

for (var x in repsToBlink){ 
    (function (id) { 
     setTimeout(function() {setblink(id)},500); 
    })(repsToBlink[x]); 
} 

该代码要求进一步改进。

如果repsToBlink是一个数组,你应该的repsToBlinkfor (...;...;...)loop over the integer indices,而不是性能(for ... in)。但是,如果您要使用带有ID索引(而不是值)的对象,则适合使用for ... in

上述火灾每个id(其可能压倒浏览器)一个单独的定时器。通过将循环移到一个函数中,该函数成为唯一需要调度的函数,只需要一个计时器。

既然你正在运行一个函数定期,setInterval是比较合适的。

每当你从repsToBlink删除和ID,检查是否有任何剩余;如果没有,则取消间隔。

(function() { 
    var repsToBlink, repCount=0, blinkInterval; 

    function startBlinking(ids) { 
     addRepsToBlink(ids); 
     if (! blinkInterval) { 
      blinkInterval = setTimeout(blinkAll, 500); 
     } 
    } 

    function addRepsToBlink(ids) { 
     for (var i=0; i<ids.length; ++i) { 
      addRep(ids[i]); 
     } 
    } 

    function addRep(id) { 
     if (! id in repsToBlink) { 
      ++repCount; 
      repsToBlink[ids[i]] = true; 
     } 
    } 

    function removeRep(id) { 
     if (id in repsToBlink) { 
      delete repsToBlink[id]; 
      --repCount; 
      if (!repCount) { 
       clearInterval(blinkInterval); 
       blinkInterval=0; 
      } 
     } 
    } 

    function blinkAll() { 
     for (id in repsToBlink) { 
      blink(id); 
     } 
    } 

    function blink(id) { 
     var elm = document.getElementById(id); 
     if (elm.color == "red"){ 
      elm.color = "black"; 
     } else { 
      elm.color = "red"; 
     } 
    } 

    window.startBlinking = startBlinking; 
    window.addRepsToBlink = addRepsToBlink; 
    window.addRep = addRep; 
    window.removeRep = removeRep; 
})(); 

您的问题是setTimeout正在全局上下文中调用。那,你马上就会调用这个函数。

的解释,当它到达此代码:

setTimeout(setblink(id),500);

立即调用setblink功能,假设该函数的返回值是什么超时应该调用。这会导致堆栈溢出,因为这是一个递归函数。

为了解决这个问题,将setTimeout函数调用到function(){}之内。