MgSam
MgSam

Reputation: 12803

jQuery Deferred - Add callbacks to the Deferred contract at runtime

I need is to add an unknown number (known only at runtime) of .pipe() calls to the functions being monitored by jQuery's .when(). These calls will be based off of ajax calls made as a result of another asynchronous operation. Please see the code below for a more clear explanation:

$.when(
    $.ajax({ 
        async: true,        
        success: function (data, textStatus, jqXhr) {
            console.log('Level 1')

            for(var i = 0; i < data.length; i++)
                jqXhr.pipe(
                    $.ajax({  
                        data: data[i],                                                              
                        async: true,        
                        success: function (data, textStatus, jqXhr) {
                            console.log('Level 2');
                        },       
                    })
                );
        },       
    }),
    $.ajax({
        async: true,        
        success: function (data, textStatus, jqXhr) {
            console.log('Level 3');
        },       
    })
).done(function(){ console.log('All done!'); });

Basically Level 1 and Level 3 need to execute in parallel. The Level 2s are all based off of the result of Level 1. And Level 1, all the Level 2s and Level 3 need to execute before All done.

Using the code above doesn't work, as the call to .pipe() does not affect what .when() is monitoring.

Is it possible to do what I want with jQuery's Deferred framework?

Thanks for any help.

Note: Earlier, I asked a very similar question, but I've realized the situation is significantly more complicated than what I illustrated there and I didn't want to cause confusion with the existing answers.

Original question

Upvotes: 1

Views: 505

Answers (1)

Felix Kling
Felix Kling

Reputation: 816374

It's not that much more complicated. If you want to execute all level 2 calls in parallel, just call $.when inside the .pipe callback and return that deferred object:

$.when(
    $.ajax({        
        // ...      
    }).pipe(function(data) {
        // concise way to make the Ajax calls for each value
        var deferreds = $.map(data, function(value) {
            return $.ajax({data: value, /*...*/});
        });
        return $.when.apply($, deferreds);
    }),
    $.ajax({        
        // ...       
    })
).done(function(){ console.log('All done!'); });

If you want to execute them sequentially, use .pipe again:

$.when(
    $.ajax({        
        // ...      
    }).pipe(function(data) {
        // A "dummy" resolved deferred object 
        var deferred = (new $.Deferred()).resolve();
        $.each(data, function(value) {
            deferred = deferred.pipe(function() {
                return $.ajax({data: value, /*...*/});
            });
        });
        return deferred;
    }),
    $.ajax({        
        // ...       
    })
).done(function(){ console.log('All done!'); });

I have to say though that you should keep the number of Ajax calls to a minimum.

Upvotes: 1

Related Questions