Javascript jquery setTimeout递归太多

Javascript jquery setTimeout递归太多,javascript,jquery,recursion,settimeout,setinterval,Javascript,Jquery,Recursion,Settimeout,Setinterval,我从多个地方读到,当设置一些基本上永远运行的东西时,setTimeout()比setInterval()更可取。下面的代码工作正常,但在运行Firefox(38.0.1)大约一个小时后,抛出了一个错误,即递归太多 基本上,我让它从counts.php获取少量文本,并用这些信息更新一个表。根据检查员的说法,整个呼叫和返回大约需要50毫秒。我正试图让它按照t的指示每x秒执行一次 我怀疑如果我切换到setInterval(),这可能会起作用,但我不确定setTimeout()与setInterval(

我从多个地方读到,当设置一些基本上永远运行的东西时,setTimeout()比setInterval()更可取。下面的代码工作正常,但在运行Firefox(38.0.1)大约一个小时后,抛出了一个错误,即
递归太多

基本上,我让它从counts.php获取少量文本,并用这些信息更新一个表。根据检查员的说法,整个呼叫和返回大约需要50毫秒。我正试图让它按照
t
的指示每x秒执行一次

我怀疑如果我切换到setInterval(),这可能会起作用,但我不确定setTimeout()与setInterval()心态的当前状态是什么,因为我发现的一切都是3-5年前的事情

$(document).ready(function() {
    t = 3000;
    $.ajaxSetup({cache: false});

     function countsTimer(t) {
        setTimeout(function () {
            $.getJSON("counts.php", function (r) {
                $(".count").each(function(i,v) {
                    if ($(this).html() != r[i]) {
                        $(this).fadeOut(function () {
                            $(this)
                                .css("color", ($(this).html() < r[i]) ? "green" : "red")
                                .html(r[i])
                                .fadeIn()
                                .animate({color: '#585858'}, 10000);
                        })
                    };
                });

                t = $(".selected").html().slice(0,-1) * ($(".selected").html().slice(-1) == "s" ? 1000 : 60000);

                countsTimer(t);
            });
        }, t);
    };
    countsTimer(t);
});
$(文档).ready(函数(){
t=3000;
$.ajaxSetup({cache:false});
函数计数器(t){
setTimeout(函数(){
$.getJSON(“counts.php”,函数(r){
$(“.count”)。每个(函数(i,v){
if($(this.html()!=r[i]){
$(此).fadeOut(函数(){
$(本)
.css(“颜色”,($(this.html()

更新:通过在.fadeOut()动画之前添加.stop(true,true)解决了此问题。这个问题只发生在Firefox中,因为在其他浏览器中的测试没有引起任何问题。我已将答案标记为正确,尽管它不是本例中的解决方案,但它提供了更一般意义上的良好解释。

在本例中,您确实应该切换到setInterval()。setInterval()的问题在于,如果要清除超时,您必须保留一个引用,如果操作(可能)执行的时间长于超时本身,则操作可能会运行两次

例如,如果您使用setInterval每1s运行一次函数,但是由于XHR请求缓慢,函数本身需要2s才能完成,那么该函数将在某个时间点同时运行两次。这通常是不可取的。通过使用setTimout并在原始函数结束时调用,函数从不重叠,您设置的超时始终是两个函数调用之间的时间

然而,在您的情况下,您似乎有一个长期运行的应用程序,因为您的函数每3秒运行一次,所以函数调用堆栈将每3秒增加一个。除非打破这个递归循环,否则这是无法避免的。例如,您只能在收到浏览器事件(如单击文档并检查时间)时执行请求

(function() 
{
    var lastCheck = Date.now(), alreadyRunning = false;
    document.addEventListener
    (
        "click", 
        function() 
        {
            if(!alreadyRunning && Date.now() - lastCheck > 3000) 
            {
                alreadyRunning = true;
                /* Do your request here! */
                //Code below should run after your request has finished
                lastCheck = Date.now();
                alreadyRunning = false;
            }
        }
    )
}());
这没有setInterval的缺点,因为您总是检查代码是否已在运行,但是检查仅在收到浏览器事件时运行。(这通常不是问题。)这种方法会产生更多的样板文件

因此,如果您确定XHR请求的完成时间不会超过3秒,只需使用setInterval()

编辑:上面的答案在某些方面是错误的


正如注释中所指出的,setTimeout()确实不会增加调用堆栈的大小,因为它在调用超时中的函数之前返回。此外,问题中的函数不包含任何特定的递归。我将保留这个答案,因为部分问题是关于setTimeout()和setInterval()的。但是,导致递归错误的问题可能出现在其他代码中,因为在示例代码中的任何地方都没有函数直接或间接地调用自身。

我不知道为什么不应该使用
setInterval
。原因是什么?听起来像是只在特定情况下才相关的虚假声明或理由。我想知道清除超时是否能解决这个问题,即使我真的不确定从哪里来的问题recursion@squint为了避免一些问题,如果请求造成的延迟超过完成时间,我猜您的问题在于队列中放置的动画太多。我无法用变通方法发布任何答案,因为我目前在平板电脑上,所以我很抱歉,但您可以使用.stop(true)测试它。我的意思是$('.count')。stop(true)。each(…);我应该补充一点,页面的用途是它将被显示,并且永远不会真正与之交互。这样它就可以在那里坐上几个小时而不让老鼠动。不使用setInterval的原因是否仅仅是因为它可能重叠并且已经在运行实例?正如您在这里所使用的,添加对
alreadyRunning
的检查是否会大大缓解该问题?在这种情况下,这是正确使用setInterval()的教科书示例。如果使用
setTimeout
setInverval
,则与问题无关,函数调用堆栈增加部分的答案不正确
countsTimer
setTimeout
中的函数执行下一次
countsTimer
调用之前,返回并从堆栈中移除自身。至少应该如此。