6

I am trying to chain promises so that doQuery(0) executes then doQuery(1), etc... sequentially until doQuery(9).

My problem is that i is always equals to 10 in the callback function.

doQuery(0) executes then doQuery(10).

How do I pass each value of i in the callback function?

var promise = doQuery(0);
for (var i = 1; i < 10; i++) {
    promise = promise.then(function() {
        doQuery(i);
    });
};
Maxime Vernier
  • 340
  • 1
  • 9
  • Read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures#Creating_closures_in_loops.3A_A_common_mistake – JB Nizet Sep 15 '13 at 21:26

2 Answers2

5

Since you're using Angular.js, you should use it's bind function here:

var promise = doQuery(0);
for (var i = 1; i < 10; i++) {
    promise = promise.then(angular.bind(null, doQuery, i));
}

Without relying on Angular.js, you could use a closure to make a copy of i for each callback function (rather than having them all share the single copy of i in the outer scope):

var promise = doQuery(0);
for (var i = 1; i < 10; i++) {
    promise = promise.then(function(i){
        return function(){
            doQuery(i);
        };
    }(i));
}

In modern Javascript engines you can also use the native Function.prototype.bind:

var promise = doQuery(0);
for (var i = 1; i < 10; i++) {
    promise = promise.then(doQuery.bind(null, i));
}
Paul
  • 139,544
  • 27
  • 275
  • 264
2

You need to return each to-be-chained promise from the then callback, otherwise it will likely fail. To pass the right i value to each callback, see JavaScript closure inside loops – simple practical example.

var promise = doQuery(0);
for (var i=0; i<10; i++) (function(ii) {
    promise = promise.then(function() {
        return doQuery(ii);
    });
})(i);
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375