jquery when/then (also when/done) not waiting

Julie Lerman picture Julie Lerman · Feb 23, 2014 · Viewed 31.1k times · Source

I've looked at many samples that use this syntax, but I can't see what I"m doing wrong. The "then" function is running before the ajax call returns.

I've tried also using $.deferred and a few other patterns to no avail.

Can someone see what I'm missing?

I have debugged and can see the calls being made from inside the done/then before the ajax call returns it's success (or error) data.

Thanks for any help.

Main call:

this.addFirstTask = function(task) {
    var totalHours = GetHours();
    $.when(totalHours).done(function (data) {
        task.TaskHours(data);
        self.add(task);
    });
};

It is calling the following ajax function:

function GetHours() {
    $.ajax({
        url: "/api/tst/GetMyData",
        type: 'GET',
        dataType: 'json',

        success: function(data) {
           return data;
        },

        error: function(data) {
            return 0;
        }
    });
};

Thanks!

post mortem:

in addition to adding the return to the ajax call, as per additional advice, I removed success & error from the ajax call and changed addFirstTask to:

this.addFirstTask = function(task) {
    var totalHours = GetHours();
    $.when(totalHours)
     .then(function (data) {task.TaskHours(data);})
     .done(function () { self.add(task); });
};

If GetHours succeeds, I update the TaskHours value. If it fails, I just skip it. I realized that DONE is like a "FINALLY" in .NET's try/catch. So rather than adding the task right away and then letting my observable binding update it when the value comes back, even the self.add is part of the asynchronous call.

Answer

Andy Smith picture Andy Smith · Feb 23, 2014
function GetHours() {
    return $.ajax({
        ...
    });
};

$.ajax() returns a Promise. $.when() takes a collection of Promises, and returns a promise that completes when all the input promises complete .then() is a method on Promise (in this case, the wrapper Promise that when() created) that calls it's first function arg when the promise resolves with success.

so, your GetHours needs to return a Promise that when() can wrap, and you call the then() on. you could actually skip the when() part and just call .then on the return from GetHours.

you aren't getting an error because .when() also takes any old object, and if it doesn't implement the Promise interface, it just treats it like an already-completed Promise.