18

I have a situation in which my ajax calls must perform in a particular order. I have used jQuery Deferred objects in other situations, but cannot seem to find a way to make this behave appropriately.

I have a function which performs a number of ajax requests in it's lifetime. Some of the requests will be performed during the success callback of other requests.

My question: is there a way to return all nested deferred objects to the original $.when call?

A simplified example would be:

function nestedAjax() {
    $.get("/", function(){
        console.log("First ajax done.");
        $.get("/", function(){
            console.log("Second ajax done.");
        });
    });
};

I am trying to have the nestedAjax function to use $.when() and $.done() like so:

$.when(nestedAjax()).done(function(){
    console.log("Complete");
});​

With the console output reading:

> First ajax done.
> Second ajax done.
> Complete.

I can return the first get to achieve this:

> First ajax done.
> Complete.
> Second ajax done.

But obviously this is not what I require. Any help would be appreciated.

3
  • If they HAVE to occur in sequence, why not perform SYNCHRONOUS requests in the first place? Stop trying to fit a square peg in a round hole. Commented Sep 5, 2012 at 2:18
  • You're right. Thanks for the wakeup call. I've managed to rearrange and achieve my desired functionality. I'm still interested however if there is a way to 'collect' deferred objects from nested ajax calls for evaluation, so my question still stands. Commented Sep 5, 2012 at 3:32
  • That's fair. :) I may not be off base here - it's very late and i've been working - but perhaps in the callback function of each AJAX call you could add the object to an array? You could either pass the array through the chain as an argument or leave it in the global space. Commented Sep 5, 2012 at 7:10

3 Answers 3

14

It's actually quite simple. Though all the AJAX calls are Deferred objects, I still use one for the method itself.

function nestedAjax() {
    var dfd = $.Deferred();
    $.get("/echo/json/", function(){
        console.log("First ajax done.");
        $.get("/echo/json/", function(){
             console.log("Second ajax done.");
            dfd.resolve();
        });
    });

    return dfd.promise();
};
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I've been using them more often and I see now why I can't do exactly what I was trying to do. Thanks for the help.
of course!! I've been banging my head against the deferred for a few hours now, just didn't make the connection. thanks Dr!!
7

You don't actually need an extra deferred object. You can do what you want by chaining with then():

function nestedAjax() {
    return $.get("/echo/json/").then(function(result1){
        console.log("First ajax done.");
        if (result1) {
            return result1;
        } else {
            return $.get("/echo/json/").then(function(nestedResult){
                console.log("Second ajax done.");
                return nestedResult;
            });
        }
    });
};

I added some logic since I think that's probably the reason you are executing this synchronously. After that you can use the result in $.when like so:

$.when(nestedAjax(), $.get("/something/else")).then(function(nested, other) {
    console.log("Complete.", nested, other);
});

3 Comments

I don't get the if/else here. Would that stop the 2nd call from being issued?Please explain.
Yes, the second Ajax call will only be issued if the result of the first is truthy.
@dmnd: I think you meant "if the result of the first is falsy."
1

Couldn´t add a comment for some reason to the above answer.

So i add my comment here. The above answer will only work if the ajax calls are fast and returns BEFORE the return dfd.promise().

I have the same problem. And as you can see. The returned deferred object states that it is "pending": http://jsfiddle.net/BtEKa/

4 Comments

Yes you're absolutely right. This is something I had concluded, and in my situation I have multiple AJAX request performing in the same function. The closest solution to my problems was to use $.ajaxComplete(), although I re-engineered my approach and made it work cleanly.
But note that if you leave it at that. The event will be triggered eventually after the object has resolved/rejected. That was my issue. My object returned a "pending" state()...the a couple of seconds later it changed and my events started to fire off.
In python there is the ability to yield a result from a control structure. This seems to be what I would need, where multiple ajax calls could yield a result and upon receiving all results a 'master' deferred object could be resolved. It's obvious that fighting a language to get certain behavior from it is usually a sign that redesign of approach is necessary.
I think the problem here is how Ajax work. It asynchronous in that sense like threading. With Ajax and deferred objects it is possible to chain ajax calls. I can post some code on how i solved my problem? The problem i had is that one ajax call was needed to return to another ajax call and they both would make up a result that was then sent back to the caller. It´s not the best code...it probably can be optimized but it worked for me. I can post my code if it would help in any way?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.