Reputation: 13800
I have a function from a library that returns a promise. I need to run this function multiple times, but each iteration must wait until the previous task is done.
My assumption was that I could do this:
promiseReturner(1)
.then(promiseReturner(2)
.then(promiseReturner(3)
.then(...)
Which could be simplified using a loop:
var p = Promise.resolve();
for (var i=1; i<=10; i++) {
p = p.then(promiseReturner(i));
}
However, when I do this each promise in the chain is executed at the same time, instead of one after the other as .then()
seems to imply. Clearly I'm missing something fundamental about promises -- but after reading several tutorials and blog posts I'm still lost.
Here's a codepen I wrote up to demonstrate my attempt.
Upvotes: 20
Views: 14561
Reputation: 21
Executing promises synchronously with respect to each other can be tricky. I've included an example below that uses Axios promises, but you can replace them with your own. Good luck!
const get = (endpoint = '/', params = {}) => {
// return axios promise
return axios({
method: 'get',
url: apiHost + endpoint,
headers: { 'Authorization': 'Token ' + this.state.token },
params: params,
});
};
get('/api/some-endpoint/')
.then((response) => {
console.log(response);
//return next promise
return get('/api/another-endpoint/');
}).then((response) => {
console.log(response);
// return next promise
return get('/api/yet-endpoint');
}).then((response) => {
console.log(response);
// return next promise
return get('/api/last-endpoint/');
}).then((response) => {
console.log(response);
// finished, no more promises left in the chain
})
.catch(function (error) {
console.log('Error getting data', error);
});
Upvotes: 0
Reputation: 7745
You can run your code via nsynjs, it will pause execution on each function that returns promise, and will wait until promise is resolved:
var promiseReturner = function(i) {
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve("result is "+i)
}, 1000);
});
};
function synchronousCode() {
for (var i=1; i<=10; i++) {
var p=promiseReturner(i); // nsynjs will pause here until promise is resolved
console.log(p.data); // `data` will contain result of the promise
}
};
nsynjs.run(synchronousCode, null, function(){
console.log("finish");
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
Upvotes: -1
Reputation: 731
If you are using es6, you can achieve this using array.reduce
. I think quite neatly.
const functions = [/* array of functions which return promises */];
const finalPromise = functions.reduce(async (promise, asyncFn) => {
await promise;
return asyncFn();
}, Promise.resolve());
Upvotes: 2
Reputation: 671
Here's a solution which I used to solve the same problem:
var recursiveFunction = function(values) {
return new Promise(function(resolve, reject) {
if (values.length <= 0) {
return resolve();
} else {
return promiseReturner(values[0]).then(function() {
values.shift();
return recursiveFunction(values).then(function() {
resolve();
});
});
}
});
}
recursiveFunction([1,2]).then(function(r) {
console.warn('Finished solving promises sequentially');
})
Upvotes: 1
Reputation: 816322
Your "non-loop" solution shouldn't work either. You have to pass a function to .then
, not a promise:
var p = Promise.resolve();
for (var i=1; i<=10; i++) {
(function(i) {
p = p.then(function() {
return promiseReturner(i);
});
}(i));
}
If that function returns a promise, then you get that chaining effect.
More info about promises on MDN.
Can be simplified with let
(and arrow functions):
var p = Promise.resolve();
for (let i=1; i<=10; i++) {
p = p.then(() => promiseReturner(i));
}
Or .bind
(which is ES5):
var p = Promise.resolve();
for (var i=1; i<=10; i++) {
p = p.then(promiseReturner.bind(null, i));
}
Upvotes: 23
Reputation: 6396
You can use async/await
using es6 generators and a library like co.
co(function* () {
while(upto < 10) {
var result = yield Promise.resolve(true);
}
return result;
}).then(function (value) {
console.log(value);
}, function (err) {
console.error(err.stack);
});
Here's some detail how this works: http://davidwalsh.name/async-generators
Upvotes: 1