0

I am trying chaining an array of jQuery Deferred objects together, with the aim to call a final function once everything is resolved.

However, I am unable to get $.when.apply($, deferreds) to work, but I can't figure out why it is not working.

function callBackend(count) {
  var deferred = $.Deferred();
  setTimeout(function() {
    $("div").append("<p>" + count + "</p>");
    deferred.resolve();
  }, 50);
  return deferred.promise();
}

$(function() {
  $("a").click(function() {
    var promises = [];
    for (i = 1; i <= 10; i++) {
      var deferred = $.Deferred();
      callBackend(i).then(function() {
        deferred.resolve();
      });
      promises.push(deferred.promise());
    }
    $.when.apply($, promises).then(function() {
      $("div").append("<p>All done!</p>");
    });
  });
});

I have created a fiddle to illustrate the problem. Anyone got an idea?

http://jsfiddle.net/YNGcm/2244/

yilik01
  • 138
  • 8

2 Answers2

1

You can use directly the deferred element createdin the callBackend.

function callBackend(count) {
  var deferred = $.Deferred();
  setTimeout(function() {
    $("div").append("<p>" + count + "</p>");
    deferred.resolve();
  }, 500);
  return deferred;
}

$(function() {
  $("a").click(function() {
    var promises = [];
    for (i = 1; i <= 10; i++) {
      var deferred = callBackend(i)
      promises.push(deferred);
    }
    $.when.apply($, promises).then(function() {
      $("div").append("<p>All done!</p>");
    });
  });
});

See http://jsfiddle.net/gaby/YNGcm/2243/

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • Thanks. This works, however any idea why my original sample does not work? – yilik01 Oct 24 '18 at 04:57
  • @yilik01 your problem was one of scope. The `var deferred = $.Deferred();` in the `for` loop was using a single variable for all the `callBackend` calls and so the `deferred.resolve();` inside the `then` was only referencing the last deferred object. All the others were never resolved. If you used `let` instead of `var` it would work. Otherwise you would need to create a closure to maintain the correct reference to the variable. – Gabriele Petrioli Oct 24 '18 at 07:13
  • @yilik01 see the answers at https://stackoverflow.com/questions/111102/how-do-javascript-closures-work – Gabriele Petrioli Oct 24 '18 at 07:16
1

Instead of Deferred object of jQuery you can directly work on Promise object itself.

function callBackend(count) {

 return new Promise((resolve,reject) => {
         (function(c){
                 setTimeout(function() {
        $("div").append("<p>" + count + "</p>");
    resolve(c);
  }, 5000);
     })(count);
 });
}

$(function() {

  $("a").click(function() {
    var promises = [];
    for (i = 1; i <= 10; i++) {
      promises.push(callBackend(i));
    }

    Promise.all(promises).then(function() {
      $("div").append("<p>All done!</p>");
    });
  });
});
front_end_dev
  • 1,998
  • 1
  • 9
  • 14