8

Reading a JSON-Service like this:

$.ajax({
  url:'activeIDs',
  success : function(data){ // data = [14,15]
    var tableRows = [];
    for (var dataIndex=0; dataIndex < data.length; dataIndex++) {
      var isLast = dataIndex == (data.length - 1);
      $.ajax({
        url: 'info?id=' + data[dataIndex],
        success: function(data2) { // "foo", "bar"
          tableRows.push(data2.name);
          if (isLast) {
            alert(tableRows.length);
          }
        }
      });
    }
  }
});

First network-trace is:

  1. activeIDs = [14,15]
  2. info?id=14 (takes 2 seconds) = "foo"
  3. info?id=15 (takes 4 seconds) = "bar"

In this case the alert gives "2".

Seconds network-trace is different:

  1. activeIDs = [14,15];
  2. info?id=14 (takes 20 seconds) = "foo" (now takes very long)
  3. info?id=15 (takes 1 second) = "bar"

In this case the alert gives 1 after one second, this is bad!!!

Question:

How to use $.Deferred instead of isLast?

Grim
  • 1,938
  • 10
  • 56
  • 123

2 Answers2

7

You'll need to wait for all requests to finish before alerting.

$.ajax({
  url:'activeIDs',
  success : function(data){ // data = [14,15]
    var tableRows = [];
    var requests = [];
    for (var dataIndex=0; dataIndex < data.length; dataIndex++) {
      var isLast = dataIndex == data.length;

      var request = $.ajax({
        url: 'info?id=' + data[dataIndex]
      }).done(function(data2) { // "foo", "bar"
        tableRows.push(data2.name);
      });

      requests.push(request);
    }

    // wait for all requests to finish here
    $.when(requests).then(function(){
      // all success functions have been called and updated things appropriately
      alert(tableRows.length);
    }
  }
});

This assumes that all requests succeed. It also looks like there are a few typos

  • Where does tableRows get updated?
  • Where is entries defined?

Edit Now using promise style success handler. Should push the result in to tableRows before calling the $.when().then callback

phuzi
  • 12,078
  • 3
  • 26
  • 50
  • 1
    This is cool, `$.when` returns a `Promise` and accepts `Defferred`s as arguments, so I think it's exactly what OP wants. – Carlo Moretti May 05 '16 at 10:10
  • Do i need the `requests`-Array? – Grim May 05 '16 at 10:11
  • 1
    Yes, you need to pass all the Deferreds in to `$.when()` – phuzi May 05 '16 at 10:57
  • Turns out was not correct, `then` triggering before join the success-handler. How to reproduce: Insert an `alert('wait');` before the `tableRows.push(data2.name);`. You will become three alerts: "wait", "wait" and "**0**" – Grim May 06 '16 at 09:07
  • 1
    Ahh, should probably use promise style from `$.ajax` rather than the success callback to allow predictable behaviour... Answer updated. Try not to use the `success` and `error` callbacks. Better to use the Deferred/Promise style – phuzi May 06 '16 at 09:18
  • Docu sais nothing about .ajax in this case, but sais something about a "notify" to complete Deferreds. – Grim May 06 '16 at 09:35
1

Why do you want $.Deferred ? Your $.ajax calls are returning a promise, so, you can use it:

var promisesArray = [];
for (var dataIndex=0; dataIndex < data.length; dataIndex++) {
  promisesArray.push($.ajax({...}));
}
 $.when.apply($, promisesArray).then(...);

(inspired by this answer)

You can use deferreds by taking this solution and passing it to a deferred if you want, but it's not neccesary:

var x = $.Deferred(function(defer){  
    var promisesArray = [];
    for (var dataIndex=0; dataIndex < data.length; dataIndex++) {
      promisesArray.push($.ajax({...}));
    }
     $.when.apply($, promisesArray).done(function(data) { defer.resolve(data); });
});
return x.promise();

(Not tested, I'm sorry)

Community
  • 1
  • 1
Tistkle
  • 500
  • 6
  • 13