Reputation: 8445
I wonder if there is a way that I can execute an array of promises waterfally? i.e. I want the next promise not to start until the current promise is resolved.
My test:
import Promise from 'bluebird'
describe('promises waterfall', () => {
const result = []
function doItLater(val, time = 50) => {
return new Promise(resolve => {
setTimeout(() => {
result.push(val)
resolve(val)
}, time)
})
}
it('execute promises one after one resolved', done => {
result.push(1)
const promiseList = [doItLater('a', 100),doItLater('b', 1),doItLater('c')]
result.push(2)
Promise.each(
promiseList,
(output) => {
result.push(output + '-outputted')
}
)
.then(
() => {
result.push(3)
console.log(result)
expect(result).to.eql([ 1, 2, 'a', 'b', 'c', 'a-outputted', 'b-outputted', 'c-outputted', 3 ])
done()
}
)
})
})
Update
Sorry if I have made it too confusing. I'm asking how I can make my test pass. Currently my test fails - the actual result is in wrong order:
[ 1,
2,
'b',
'c',
'a',
'a-outputted',
'b-outputted',
'c-outputted',
3 ]
Upvotes: 2
Views: 1057
Reputation: 770
// Promisse waterfall pattern
var promises = [1,2,3].map((guid)=>{
return (param)=> {
console.log("param", param);
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}
}).reduce(function (acc, curr, index) {
return acc.then(function (res) {
return curr(res[index-1]).then(function (result) {
console.log("result", result);
res.push(result);
return res;
});
});
}, Promise.resolve([]));
promises.then(console.log);
Upvotes: 0
Reputation: 239573
When you create promises like this
[doItLater('a', 100),doItLater('b', 1),doItLater('c')]
they are already executing asynchronously. There is no way of controlling their order of execution.
You can use Promise.reduce
for your case, like this
Promise.reduce([['a', 100], ['b', 1], ['c']], function(res, args) {
return doItLater.apply(null, args).then(function(output) {
res.push(output + '-outputted');
return res;
});
}, result)
.then(function(accumulatedResult) {
....
});
Now, we are creating promises one by one, after the previous promise is resolved and we are accumulating the result in res
(which is actually result
). When all the promises are resolved, the accumulatedResult
will have all the values.
Note: It is strongly recommended NOT to share data between functions. Please make sure that you have compelling reasons to do so, if you have to do.
Upvotes: 2