JavaScript asynchronous return value / assignment with jQuery [duplicate]


I have the following jQuery Function. I'm trying to return the GUID value shown here in the alert(); The alert works fine and the value is populated, however I can't seem to assign it to a variable and return its value.

Ultimately I need to access the GUID value in other functions, etc. Everything I've tried only displays as undefined.

I'd like to do something like this:

function trackPage(){
    var elqTracker = new jQuery.elq(459);
    elqTracker.pageTrack({
        success: function() {
            elqTracker.getGUID(function(guid) {
                alert(guid);
                var returnValue = guid;
            });
        }
    });
    return returnValue;
}

var someGuid = trackPage();

So, this question has been asked a million times over, and I'm sure that everyone (myself included) tried this once.

It is just the nature of an asynchronous call, you can't use their results as a return value. Thats why they have you passing in a function that gets the result of the call, they can't return it either! Also notice that the elqTracker.pageTrack() function call returns IMMEDIATELY, therefore your returnValue is simply undefined.

Most people (see dfsq's answer) solve this problem by introducing a callback function as a paramater. This method is tried, and true – however jQuery has $.Deferred. This allows you to make your own asynchronous logic return a promise which you can then attach any number of callbacks to:

function trackPage(){
    var elqTracker = new jQuery.elq( 459 ),
        dfd = $.Deferred();

    elqTracker.pageTrack({
        success: function() {
            elqTracker.getGUID(function( guid ) {
                dfd.resolve( guid );
            });
        }
    });

    return dfd.promise();
}

// example use:
trackPage().done(function( guid ) {
    alert( "Got GUID:" + guid );
});

Notice now that your trackPage() returns an object that you can attach callbacks to? You don't have to attach them immediately either.

var pageHit = trackPage().done(function( guid ) {
    alert( "Page Hit GUID:" +guid );
});

$("button").click(function() {
    pageHit.done( function( guid ) {
        alert( "Clicked on Page GUID:" + guid );
    });
});

Also, the jQuery AJAX module always returns promises as well, so the interface for all your AJAX stuff should be very similar if you make your own logic return promises.


As a side note: I'd like to point out that your var returnValue was in the wrong "scope" anyway. It needed to be declared in the outer scope of the trackPage function. Even with this fix, the concept still doesn't work.


Since you have asynchronous call the way you are trying to write code is not going to work (because by the moment of return returnValue; in the trackCode return value is not yet defined). Instead you should pass callback into trackPage:

function trackPage(callback) {
    var elqTracker = new jQuery.elq(459);
    elqTracker.pageTrack({
        success: function() {
            elqTracker.getGUID(function(guid) {
                alert(guid);
                // Instead of this: var returnValue = guid;
                // You should use your callback function
                callback(guid);
            });
        }
    });
    return returnValue;
}

trackCode(function(guid) {
    // perform some actions with guid
});