Javascript如何管理递归调用?

jse*_*ano 8 javascript

我一直在玩JavaScript,并注意到一种奇怪的行为(至少对我来说很奇怪......)

所以我在这里做了一个SSCCE:

我有一个名为"myDiv"的div

function changeText(text){
    document.getElementById("myDiv").innerHTML=text;
}

function recursiveCall(counter){
    if(counter){
        setTimeout(function(){
            recursiveCall(--counter);
            changeText(counter);
        },750);
    }
}

recursiveCall(10);
Run Code Online (Sandbox Code Playgroud)

实例:http://jsfiddle.net/T645X/

所以我正在更改div上的文本,发生的是文本从9变为0,而我认为从0到9,因为递归changeText(counter);调用是在调用实际更改的方法之前文本.

Ben*_*aum 8

该函数包含异步的超时.

setTimeout(function(){
    recursiveCall(--counter);// calls the next function, which will call the next 
                             // and print in a timeout
    changeText(counter);  // print
},750);
Run Code Online (Sandbox Code Playgroud)

在递归调用到达超时之前更改文本.

如果您愿意,可以从超时外部移动打印调用,这将导致预期的行为:

function recursiveCall(counter){
    if(counter){
        recursiveCall(--counter);            
        setTimeout(function(){
            changeText(counter);
        },750);
    }
}
Run Code Online (Sandbox Code Playgroud)

(虽然,请注意,这里的打印时间不同,我们在某种程度上依赖于未定义的行为,假设它首先打印只是因为我们把计时器放在第一位)

如果您希望它仍然延迟打印,您可以告诉它已完成的功能.递归仍将在最初完成,但每个级别将告诉它上面的级别它已完成:

function recursiveCall(counter,done){
    if(counter){
        // note how recursion is done before the timeouts
        recursiveCall(counter-1,function(){ //note the function
            setTimeout(function(){          //When I'm done, change the text and let the 
                changeText(counter-1);      //next one know it's its turn.
                done(); // notify the next in line.
            },750);
        });
    }else{
        done(); //If I'm the end condition, start working.
    }
}
Run Code Online (Sandbox Code Playgroud)

这是实现这一点的小提琴.

  • @anakata我只是想让你知道你得到一个如此快速的答案(以及一个upvote)的原因是因为你很好地表达了你的问题并且它包含一个简单的可重复的例子.阅读手册的道具很高兴我可以帮忙:) (5认同)
  • @elclanrs将其他参数传递给`setTimeout`是非标准的 (2认同)