Silvan
Silvan

Reputation: 55

Javascript closure function doesn't return the right value

I have a problem with my Javascript code and don't know why it doesn't run.

This is my timer:

var time = 0;
startTimer();

function startTimer(){
    setInterval(function(){
    time=time+1;
    },10);
}

This code here works (I run timeoutTester() while clicking on a button, then it alerts and shows me the time difference):

function timeoutTester(){
    var snap_time1 = time;
    setTimeout(function(){
        var snap_time2 = time;
        var diff = snap_time2-snap_time1;
        alert(diff);            //works: ~100 everytime...
    },1000);
}

But this code here doesn't work (I run testTimer() by clicking on a button):

function timeoutTester(){
    var snap_time1 = time;
    var result;
    setTimeout(function(){
        var snap_time2 = time;
        result = snap_time2-snap_time1;
    },1000);
    alert(result); //doesn't work! It always shows me: "undefined"
    return result;
}

function testTimer(){
    var counter = 0;
    setInterval(function(){
        counter = counter + 1;
        alert(counter);         //works: 1,2,3,....
        var result = timeoutTester();
        alert(result);  //doesn't work! It always shows me: "undefined"
    }, 3000);
}

Do you know where the problem might be? (No error while debugging in browser!)

UPDATE:

I learned that alert(result); is executed immediately, while result has no value yet.

But since I'm calling timeoutTester() from the outside, I still need a return value from this function!

Any ideas?

Upvotes: 3

Views: 154

Answers (2)

Marcus
Marcus

Reputation: 1232

To get this done, you need to use a global:

var timeoutTesterResult;

function timeoutTester(){
    var snap_time1 = time;
    var result;
    setTimeout(function(){
        var snap_time2 = time;
        timeoutTesterResult = snap_time2-snap_time1;
        alert(timeoutTesterResult);                    //works: ~100
    },1000);
}

And a second timeout who gets this global only after it's set/changed:

function testTimer(){
    var counter = 0;
    setInterval(function(){
        counter = counter + 1;
        alert(counter);         //works: 1,2,3,....
        timeoutTester();
        setTimeout("alert(timeoutTesterResult)",1000); //works: ~100
    }, 3000);
}

That's the "via global"-solution.

Upvotes: 1

Ted Hopp
Ted Hopp

Reputation: 234795

In your last example (the one that doesn't work), calling setTimeout(function()...) does not execute the function immediately, but does return immediately. When it returns, result is still undefined because the function has not yet executed.

By the same token, the previous example (that has the call to alert() inside the timeout function) works because the call to alert() happens after result is assigned a value.

If for whatever reason you don't want to call alert() directly from within the timeout function, you could rewrite the last example as:

function timeoutTester(){
    var snap_time1 = time;
    setTimeout(function(){
        var snap_time2 = time;
        alertResult(snap_time2-snap_time1);
    },1000);
}
function alertResult(result) {
    alert(result);
}

(By the way, the call startTimer(1000000000000); looked scary until I realized that the argument was being ignored. :-).)

Upvotes: 4

Related Questions