Juw
Juw

Reputation: 2089

Deferred object returned before it is rejected or resolved?

I have a function that basically looks like this:

function defTest()
{
    var dfd = new jQuery.Deferred();
    $.ajax(
    {
        type: "GET",
        url: 'http://XXXX',
        cache: false,
        dataType: "json",
        success: function(data,status)
        {
            console.log('ajax done: success');
            dfd.resolve();
        },
        error: function(data,status)
        {
            console.log('ajax done: fail');
            dfd.reject();

        }
    });
    console.log('about to return dfd');
    return dfd;    
}

I call it like this:

defTest().then(.....);

The console log produce this: about to return dfd code.js:106 ajax done: success code.js:96

What confuses me is that the code seems to work. Still the dfd is returned BEFORE the ajax has finished. So i removed the return dfd. And put it last in each ajax handler function to make sure that this will NOT be returned until the Ajax has finished.:

success: function(data,status)
{
    console.log('ajax done: success');
    dfd.resolve();
    return dfd;
}

Then it didn´t work at all. I am confused! Can someone explain to me why my deferred can´t be in the ajax success and error handlers and why it works even though it seems that my deferred object returns even if it is fired BEFORE the Ajax is finished and then be resolved or rejected? How is that even possible?

EDIT: This issue is directly linked to my previous unanswered and more complex function: Problems with deferred object

This is why i can´t just "return ajax(...)" because my real function contains other ajax calls that will be apart of ONE result handed back to the caller.

Upvotes: 0

Views: 4393

Answers (5)

grantwparks
grantwparks

Reputation: 1153

Of course it's returned right away, that's the point. One would be returning the promise member of the deferred object, normally, though -- although you could return the deferred object and use returnedDeferredObject.promise().then() in code that calls this function.

If you have processing that's dependent on the AJAX completion, that processing goes in the .then() function of the returned .promise(). The beauty is in that while the asynchronous processing is going on, you can do other things that aren't dependent on the AJAX return. You can pass that returned .promise() around to other code.

var mydata = somethingThatReturnsPromise(args);

// do a whole bunch of things

mydata.then(function (returnedReponse) {
    // do stuff with returnedResponse that doesn't require DOM ready
});

$(function () {
    mydata.then(function (returnedResponse) {
        // do DOM stuff with returnedPromise
    });
});

I hope I'm not missing your point, but I like to think of that returned promise as a data source that I can use again and again later on, and the .then() callbacks I specify will only be executed once there's a returnedResponse.

As a side note, I am pretty sure that with jQuery going more towards the promise standard, .done(), .pipe(), .fail() and .progress() should be replaced with use of .then(successCb, failCb, progressCb).

Upvotes: 1

Dana McIntosh
Dana McIntosh

Reputation: 1

I believe that your problem is that you are returning the entire deferred object, rather than that object's promise.

The promise, afiak, is always returned before the asynch call is returned, so while your last console.log will trigger before the PROMISE is returned, it will happen well before the ajax is resolved.

using .then() is also probably not what you want, since it fires no matter what the status of the deferred object is: http://api.jquery.com/deferred.then/

You probably want .done()

Try this:

function defTest()
{
    var dfd = $.Deferred();
    $.getJSON("http://XXXX").done(function(data,success){
      console.log('ajax done: success');
      dfd.resolve(data);
    }).fail( function(data,status) {
      console.log('ajax done: fail');
      dfd.reject();
    });
    console.log('about to return dfds promise');
    return dfd.promise;    
}
defTest().done(function(data){ console.log(data); });

Upvotes: 0

Parv Sharma
Parv Sharma

Reputation: 12705

there are many questions like this
the AJAX request is async in nature so in the first example when you were returning it in the last line.
it dosent wait for the async ajax to complete
and in the second case the function is already over and putting return in success would obviously not return anything as you are not calling the method assigned to success event directly
UPDATE:- after the comment
because after returning the deffered object you are doing defTest().then(.....);
so the function inside the then handler will obviously be fired when the deffered object is resolved.
probably you should check the value of the deffered object as soon as you return it and not using .then() and you will get what mistake you are making here
Update 2 -
have a look here http://jsfiddle.net/BtEKa/ im getting predictable results

Upvotes: 1

Guillaume Poussel
Guillaume Poussel

Reputation: 9822

Your call to defTest will return as soon as your ajax call is started. It will not wait until deferred is resolved or not.

But you are perfectly able to do what you want:

defTest().then(function() { console.log("deferred done"); })

It will print deferred done when deferred is finally resolved.

By the way, as suggested by xdazz, $.ajax returns already a Deferred.

Upvotes: 1

xdazz
xdazz

Reputation: 160853

$.ajax returns a Deferred object, so you only need to return it.

return $.ajax(...

Upvotes: 1

Related Questions