Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Javascript manages recursive calls?

Tags:

javascript

I was goofing around with JavaScript, and a notice a strange behavior (strange for me at least. . .)

So I did a SSCCE here it goes:

I have a div named "myDiv"

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

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

recursiveCall(10);

Live example: http://jsfiddle.net/T645X/

So I'm changing the text on the div, and what happens is that the text goes from 9 to 0, while I thought that it was suppose to go from 0 to 9, since the recursive changeText(counter); call is before calling the method that actually changes the text.

like image 468
jsedano Avatar asked Jul 26 '13 22:07

jsedano


1 Answers

The function contains a timeout which is asynchronous.

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

The text is changed before the recursive call hits the timeout.

If you'd like to, you can move the print call from outside the timeout, which would result in the expected behavior as such:

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

(Although, note that here the printing is not timed apart, and we're relying somewhat on undefined behavior assuming it'd print first just because we put the timer first)

If you would like it to still print in delays, you can tell the function it's done. Recursion will still be done initially, but each level will tell the level above it that it is done:

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.
    }
}

Here is a fiddle implementing this.

like image 66
Benjamin Gruenbaum Avatar answered Sep 23 '22 17:09

Benjamin Gruenbaum