I have the following situation:
var ids = [120, 121, 122, 123, 124]
function dummyPromise(pause) {
var deferred = Q.defer();
setTimeout(function() {
console.log(pause);
deferred.resolve(pause);
}, pause);
return deferred.promise;
}
for(var i = 0; i < ids.length; i++) {
dummyPromise(ids[i])
.then(dummyPromise)
.then(dummyPromise)
.then(dummyPromise)
.then(dummyPromise)
.done(function(){
console.log('done')
})
}
I want to wait for chains to complete before iterating to next. Whats the best way to approach this?
In these examples I use standard Promise
s. If you need to use (the awesome) Q library, you can make it shorter by substituting Q.fcall(fn, arg)
in places of Promise.resolve(arg).then(fn)
or using Q()
instead of Promise.resolve()
.
By chaining promises
var q = Promise.resolve();
for (var i = 0; i < 10; i++) {
(function(item, index){
q = q.then(function() {
return // do async stuff here
});
})(ids[i], i);
}
q.then(function() {
// all iterations finished
});
With arrays
function forEachAsync(arr, fn) {
var index = 0;
function next() {
if (index < arr.length) {
var current = index++;
return Promise.resolve().then(function() {
return fn(arr[current], current, arr);
}).then(next);
}
}
return Promise.resolve().then(next);
}
...
forEachAsync(ids, function(item, idx) { ... }).then(...)
With iterables
function forOfAsync(iterable, fn) {
var iterator = iterable[Symbol.iterator]();
function next() {
var iteration = iterator.next();
if (iteration.done) {
return iteration.value;
} else {
return Promise.resolve(iteration.value).then(fn).then(next);
}
}
return Promise.resolve().then(next);
}
forOfAsync(ids, function(id) { ... }).then(...)
With async-await
for (let id of ids) {
await doSomeAsyncStuffWithId(id);
}
Using array#reduce - your code would look like
ids.reduce(function(prev, id) {
return prev
.then(function() {
return dummyPromise(id)
})
.then(dummyPromise)
.then(dummyPromise)
.then(dummyPromise)
.then(dummyPromise)
.then(function(){ // if you do done you can't chain
console.log('done')
});
}, Q(null))
.done(function() { // done here though
console.log('all done');
});
Thanks to https://github.com/jprichardson/node-batchflow . I ended using this approach: See fiddle: https://jsfiddle.net/c9fxqhs5/
var ids = [120, 121, 122, 123, 124]
function dummyPromise(pause) {
var deferred = Q.defer();
setTimeout(function() {
console.log(pause);
deferred.resolve(pause);
}, pause);
return deferred.promise;
}
function again(i) {
if (i < ids.length) {
$('body').append('<p>processing: ' + i + '</p>');
dummyPromise(ids[i])
.then(dummyPromise)
.then(dummyPromise)
.then(dummyPromise)
.then(dummyPromise)
.done(function(result){
$('body').append('<p>done: ' + i + ' result=' + result + '</p>');
again(i+1)
})
} else {
console.log('All Done.')
}
}
again(0)