Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 399
Julie Lerman Avatar asked Feb 23 '14 21:02

Julie Lerman


People also ask

When and then in jQuery?

Working of the jQuery when() functionThe jQuery when() function gives a way to execute one or more objects of the callback function. The object when we pass to the when() function, will return promise objects which conform to the specification with the passed thenable object.

When jQuery deferred?

Deferred() method in JQuery is a function which returns the utility object with methods which can register multiple callbacks to queues. It calls the callback queues, and relay the success or failure state of any synchronous or asynchronous function.

Is jQuery asynchronous?

You can use jQuery to support both synchronous and asynchronous code, with the `$. when` function, and your code doesn't have to care whether or not it's async.

How AJAX works?

AJAX allows web pages to be updated asynchronously by exchanging small amounts of data with the server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page. Classic web pages, (which do not use AJAX) must reload the entire page if the content should change.


2 Answers

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.

like image 93
Andy Smith Avatar answered Oct 30 '22 15:10

Andy Smith


This is not be the OPs issue, but I had something similar happen and it was because I was calling $.when(...) incorrectly by passing an array of promises.

Per the documentation for jQuery.when if you want to wait for multiple Deferred objects you must make the call as such:

$.when( d1, d2 ).then(....);

That means that if you have multiple deferred objects in an array you should use apply(...), otherwise $.when will not work properly. So your call for an array of deferred objects would look like this:

$.when.apply(this, arrayOfDeferred).then(....);

Here is a JS Fiddle demonstrating this:

https://jsfiddle.net/Lvo4hrez/11/

like image 20
virtualadrian Avatar answered Oct 30 '22 16:10

virtualadrian