How could I fire off promises one after the other?
waitFor(t)
, is a function that returns a promise that resolves after t
time. What I wish to be able to do with that is:
waitFor(1000) Then when finished, console.log('Finished wait of 1000 millis') then
waitFor(2000) Then when finished, console.log('Finished wait of 2000 millis') then
waitFor(3000) Then when finished, console.log('Finished wait of 3000 millis')
Here is what I tried:
waitFor(1000).then(function(resolve, reject) {
console.log(resolve);
}).then(waitFor(2000).then(function(resolve, reject) {
console.log(resolve);
})).then(waitFor(3000).then(function(resolve, reject) {
console.log(resolve);
}));
Unfortunately this console.logs the statements each 1 second after another, which means that the promises where all called at once.
I managed to fix this with callbacks like so, yet that makes everything very ugly:
waitFor(1000).then(function(resolve, reject) {
console.log(resolve+' @ '+(new Date().getSeconds()));
waitFor(2000).then(function(resolve, reject) {
console.log(resolve+' @ '+(new Date().getSeconds()));
waitFor(3000).then(function(resolve, reject) {
console.log(resolve+' @ '+(new Date().getSeconds()));
});
});
});
So how should I do this with promises that makes it work, yet isn't using ugly callback hell?
Undesired result: /
Desired result: /
How could I fire off promises one after the other?
waitFor(t)
, is a function that returns a promise that resolves after t
time. What I wish to be able to do with that is:
waitFor(1000) Then when finished, console.log('Finished wait of 1000 millis') then
waitFor(2000) Then when finished, console.log('Finished wait of 2000 millis') then
waitFor(3000) Then when finished, console.log('Finished wait of 3000 millis')
Here is what I tried:
waitFor(1000).then(function(resolve, reject) {
console.log(resolve);
}).then(waitFor(2000).then(function(resolve, reject) {
console.log(resolve);
})).then(waitFor(3000).then(function(resolve, reject) {
console.log(resolve);
}));
Unfortunately this console.logs the statements each 1 second after another, which means that the promises where all called at once.
I managed to fix this with callbacks like so, yet that makes everything very ugly:
waitFor(1000).then(function(resolve, reject) {
console.log(resolve+' @ '+(new Date().getSeconds()));
waitFor(2000).then(function(resolve, reject) {
console.log(resolve+' @ '+(new Date().getSeconds()));
waitFor(3000).then(function(resolve, reject) {
console.log(resolve+' @ '+(new Date().getSeconds()));
});
});
});
So how should I do this with promises that makes it work, yet isn't using ugly callback hell?
Undesired result: http://jsfiddle/nxjd563r/1/
Desired result: http://jsfiddle/4xxps2cg/
Share Improve this question edited Oct 21, 2015 at 6:01 Max asked Oct 21, 2015 at 5:55 MaxMax 2,8462 gold badges26 silver badges35 bronze badges 3- This might help - tech.transferwise./making-serial-xhr-calls-in-angularjs – FrailWords Commented Oct 21, 2015 at 6:03
- I'm not even using angularjs.... – Max Commented Oct 21, 2015 at 6:04
- I pointed to the blog to get an idea - go for a recursive function which will go through your array of promises. – FrailWords Commented Oct 21, 2015 at 6:06
4 Answers
Reset to default 3I found your solution.
You need to have each then
to return a new promise, so that the next then
can react once the previous one has been resolved.
waitFor(1000).then(function(result) {
$('#result').append(result+' @ '+(new Date().getSeconds())+'<br>');
return waitFor(2000);
}).then(function(result) {
$('#result').append(result+' @ '+(new Date().getSeconds())+'<br>');
return waitFor(3000);
}).then(function(result) {
$('#result').append(result+' @ '+(new Date().getSeconds())+'<br>');
});
jsfiddle http://jsfiddle/4xxps2cg/2/
You can put promises into array and use reduce
to chain them, starting with one extra resolved promise.
function waitPromise(time) {
//console.log(time);
return new Promise( (resolve,reject) => {
setTimeout( () => {resolve('resolved');}, time);
});
}
function log(data) {
return new Promise( (resolve,reject) => {
console.log( data +' @ '+(new Date().getSeconds()));
resolve();
});
}
var ps = [];
for (var i=0;i<3;i++) {
let time = (i+1) * 1000;
ps.push( () => waitPromise(time) );
ps.push( log );
}
console.log( 'started' +' @ '+(new Date().getSeconds()));
var p = Promise.resolve();
ps.reduce( (p,c) => {return p.then(c)}, p);
The format for calling and waiting is a bit off, your then
should be a function that returns a promise, since now you're passing a function call instead of a function, its running that request instantly instead of waiting to call the function as a result of the promise.
This should do it:
function waitFor(timeout) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(`Finished waiting ${timeout} milliseconds`);
}, timeout);
});
}
waitFor(1000).then(function(resolve, reject) {
$('#result').append(resolve+' @ '+new Date().getSeconds()+'<br/>');
}).then(function(){
return waitFor(2000)
}).then(function(resolve, reject) {
$('#result').append(resolve+' @ '+new Date().getSeconds()+'<br/>');
}).then(function() {
return waitFor(2000)
}).then(function(resolve, reject) {
$('#result').append(resolve+' @ '+new Date().getSeconds()+'<br/>');
})
waitFor()
appear to be called immediately at .then()
; try returning waitFor()
from within .then()
anonymous function.
Could alternatively create array of duration values , use Array.prototype.shift()
to call waitFor
with each duration value in succession , or pass parameter timeout
to waitFor
; if same process called at each .then()
, include process at .then()
chained to Promise
in waitFor
; call same function waitFor
at .then()
chained to initial waitFor()
call
var t = [1000, 2000, 3000];
function waitFor(timeout) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("`Finished waiting ${timeout} milliseconds`");
}, timeout && t.shift() || t.shift());
}).then(function (data) {
$('#result').append(data + ' @ ' + new Date().getSeconds() + '<br/>');
})
}
waitFor().then(waitFor).then(waitFor)
//.then(function() {return waitFor(5000)})