Richard
Richard

Reputation: 65510

How to chain two promises with Ajax calls and combine the results?

I have this code:

loadData: function() {
    return new Promise(function(resolve, reject) {
        $.ajax({ dataType: 'json', url: url1}).done(function(r) { resolve(r); });               
    });
},

drawGraph: function(stats) {
    // do stuff with the stats
},

// lower down...
this.loadData().then(this.drawGraph);

It works fine. But now I want to make another Ajax call and combine data the two results, before calling drawGraph.

This is what I've tried:

loadSiteTraffic: function() {
    return new Promise(function(resolve, reject) {
        return $.ajax({ dataType: 'json', url: url1}).done(function(r) { resolve(r); });                
    }).then(function(results1) {
        return $.ajax({ dataType: 'json', url: url2}).done(function(r) { resolve(r); });
    }).then(function(results1, results2) {
        return results1 + results2;
    });
}

But now I'm getting Uncaught ReferenceError: resolve is not defined on the second time that resolve appears.

I guess this is something about how I pass resolve to the second call. But I want to hang on to the results of the first call. What should I be doing instead?

Maybe I need to make two separate loadData functions, call one from the other, and somehow combine the results in a third function...?

Upvotes: 0

Views: 1046

Answers (4)

Faly
Faly

Reputation: 13346

You can create a generic method that wrap the ajax call and returns promise:

load: function(param) {
    return new Promise(function(resolve, reject) {
        $.ajax(param).done(function(r) { resolve(r); });          
    });
},

loadData: function() {
    var res1;
    return this.load({ dataType: 'json', url: url1}).then(function(results1) {
        res1 = results1;
        return this.load({ dataType: 'json', url: url2});
    }).then(function(res2) {
        return res1 + res2;
    });
},

drawGraph: function(stats) {
    // do stuff with the stats
},

// lower down...
this.loadData().then(this.drawGraph);

If the second call doesn't depends on the first call, you can use promise.all:

load: function(param) {
  return new Promise(function(resolve, reject) {
    $.ajax(param).done(function(r) { resolve(r); });          
  });
},

loadData: function() {
    return Promise.all([
        this.load({ dataType: 'json', url: url1}),
        this.load({ dataType: 'json', url: url2}),
    ]).then(function([results1, results2]) {
        return results1 + results2;
    });
},

drawGraph: function(stats) {
    // do stuff with the stats
},

// lower down...
this.loadData().then(this.drawGraph);

Upvotes: 0

Michael Lorton
Michael Lorton

Reputation: 44376

First, you need to make a general function that makes a promise from your AJAX calls:

const ajaxPromise = url => 
 new Promise(resolve => 
        $.ajax({ dataType: 'json', url}).done(r => resolve(r); );               
    );

Now, you can either just invoke both of them:

Promise.all(ajaxPromise(url1),
            ajaxPromise(url2))
  .then([results1, results2]) => results1 + results2);

or if you really need them chained:

ajaxPromise(url1)
  .then(results1 =>
     ajaxPromise(url2)
      .then(results2 => results1 + results2));

Upvotes: 0

Stephan T.
Stephan T.

Reputation: 6074

I normally do my ajax calls like this:

$.ajax({ 
    dataType: 'json', 
    url: url1,
    success: function (res1) {
       // Do stuff with res1
       $.ajax({ 
          dataType: 'json', 
          url: url2,
          success: function (res2) {
             // Do stuff with res2
             return res1 + res2;
          ),
       });
    ),
});

This way the calls are "waiting" for each other to finish.

Upvotes: 0

31piy
31piy

Reputation: 23859

What you're currently doing is an overkill. You don't need the the Promise constructor wrapper over $.ajax call (unless you're doing some complex async operations underneath), as $.ajax already exposes promise-like then handlers.

Additionally, both of your calls don't depend on each other. So you can simultaneously make both the calls and combine the results using $.when:

loadSiteTraffic: function() {
    return $.when({
      result1: $.ajax({ dataType: 'json', url: url1}),
      result2: $.ajax({ dataType: 'json', url: url2})
    })
    .then(function(resp) {
      return resp.result1 + resp.result2;
    });
}

In your code, you encounter the undefined resolve as it is not available to the then callback.

Upvotes: 2

Related Questions