停止递归函数中的setTimeout。

14

我的问题是我无法停止计时器。

我从这个论坛中获取了一个方法来设置超时。它应该把标识符存储在全局变量中。但是,偶然发现在隐藏“mydiv”后它仍在运行。

我现在还需要知道递归函数是否为超时创建多个实例,还是只创建一个实例。因为一开始我认为每次都会覆盖“var mytimer”。现在我不太确定了。

有什么可靠的方法可以停止计时器吗?

var updatetimer= function () {
//do stuff
        setTimeout(function (){updatetimer();}, 10000);

}//end function


//this should start and stop the timer
$("#mybutton").click(function(e) { 
         e.preventDefault();
         if($('#mydiv').is(':visible')){
                   $('#mydiv').fadeOut('normal');
             clearTimeout(updatetimer);

        }else{
                   $('#mydiv').fadeIn('normal');
                   updatetimer();
               }
});

谢谢,Richard

7个回答

25

我认为大多数人都能理解为什么这段代码没有起作用了,但是我想提供给你更新后的代码。它与你的代码几乎相同,只是将超时时间赋值给一个变量,以便可以清除它。

此外,在setTimeout中使用匿名函数很好,如果你想要在函数内联运行逻辑、更改函数内的'this'的值或向函数传递参数。如果你只想调用一个函数,只需将函数名称作为第一个参数传递即可。

var timer = null; 

var updatetimer = function () {
    //do stuff

    // By the way, can just pass in the function name instead of an anonymous
    // function unless if you want to pass parameters or change the value of 'this'
    timer = setTimeout(updatetimer, 10000);
};

//this should start and stop the timer
$("#mybutton").click(function(e) { 
     e.preventDefault();
     if($('#mydiv').is(':visible')){
        $('#mydiv').fadeOut('normal');
        clearTimeout(timer);  // Since the timeout is assigned to a variable, we can successfully clear it now

    } else{
        $('#mydiv').fadeIn('normal');
        updatetimer();
   }
});

7
我认为你误解了“setTimeout”和“clearTimeout”的使用。
如果你想设置一个稍后需要取消的计时器,请使用以下方式:
foo = setTimeout(function, time);

然后调用。
clearTimeout(foo);

如果您想取消该定时器。

希望这可以帮助您!


我认为这很糟糕 - 它是可用的,但没有办法取消它(因为setTimeout的值没有被捕获),但这很容易修复,相比每秒钟发出一次请求来说微不足道。在我看来,这真的太过分了。 - annakata
谢谢,现在我自己的代码都看不懂了。使用那些匿名函数有什么优势呢?请查看链接。 - Richard
那是一个完全不同的问题,因为答案相当广泛 :) - annakata
1
我认为最简单的方法就是在递归函数中使用clearTimeout(foo)和foo=setTimeout(function,10000)。由于计时器的作用,该函数会不断地调用自身,从而实现递归。 - Richard
有没有什么(简短的)合理理由来使用像提供链接和我的代码中的那些匿名函数?否则就算了吧。我就不会使用它了。 - Richard

2

如所写,mytimer是一个从未拥有超时标识符值的函数,因此您的clearTimeout语句将不起作用。

我这里没有看到任何递归,但您需要存储setTimeout返回的值,并且如果您需要将其与多个潜在事件配对,则需要将其存储在可以查找的键值(例如元素ID)中。


我理解你的意思。 - Richard

2
这是一个简单的伪代码,用于控制和调节递归setTimeout函数。
    const myVar = setTimeout(function myIdentifier() {

    // some code

    if (condition) {
        clearTimeout(myIdentifier)
    } else {
        setTimeout(myIdentifier, delay); //delay is a value in ms.
    }

}, delay);

1

您无法停止所有创建的函数,相反,将函数转换为setInterval(表示您递归函数的相同逻辑)并停止它:


// recursive
var timer= function () {
// do stuff
  setTimeout(function (){timer();}, 10000);
}

使用setInterval的相同逻辑:


 // same logic executing stuff in 10 seconds loop
 var timer = setInterval(function(){// do stuff}, 10000)

停止它:


 clearInterval(timer);

0

(function(){

$('#my_div').css('background-color', 'red');
$('#my_div').hover(function(){
var id=setTimeout(function() {
    $('#my_div').css('background-color', 'green');
}, 2000);

var id=setTimeout(function() {
    $('#my_div').css('background-color', 'blue');
}, 4000);
var id=setTimeout(function() {
    $('#my_div').css('background-color', 'pink');
}, 6000);

    })

$("#my_div").click(function(){  
        clearTimeout(id);

        })

})();


0

如上所述,这段代码无法正常工作的主要原因是您将错误的内容传递到了clearTimeout调用中 - 您需要在updateFunction中存储setTimeout调用的返回值,并将this传递给clearTimeout,而不是函数本身的引用。

作为第二个改进建议 - 每当您拥有所谓的递归超时函数时,最好使用setInterval方法,该方法会定期运行函数直到取消。 这将实现您尝试使用updateFunction方法完成的相同任务,但更加简洁,因为您只需要在延迟函数中包含“执行操作”逻辑,并且可能更具性能,因为您不会创建嵌套闭包。此外,这是正确的方法,这一点肯定很重要,对吧? :-)


从 https://dev59.com/WnRB5IYBdhLWcg3wET1J 的讨论来看,setInterval并不总是更好。 - billyswong
是的,仅从那次讨论中,你就会得到这样一种观念,即它倾向于使用超时作为首选方法。因为setinterval例如排队。我不知道嵌套闭包。也许你对此是正确的。 - Richard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接