Reputation: 123
I'm trying to chain a sequence of Promise
s so that the second promise will start after the first one resolves and so on. I don't understand how I cannot get it to work correctly.
Here is my demo code:
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, 'a'); });
const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, 'b'); });
const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, 'c'); });
promise1.then(val => {
console.log('promise 1', val);
promise2.then(val2 => {
console.log('promise 2', val2);
promise3.then(val3 => {
console.log('promise 3', val3);
});
});
});
So what I expected from this code goes like this:
--- 5 seconds passes ---
// console outputs: 'promise 1a'
--- 5 seconds passes ---
// console outputs: 'promise 2b'
--- 5 seconds passes ---
// console outputs: 'promise 3c'
But instead what happens:
--- 5 seconds passes ---
// console outputs: 'promise 1a'
// console outputs: 'promise 2b'
// console outputs: 'promise 3c'
Why is this so? Why are all three promises triggered at the same time?
Upvotes: 1
Views: 779
Reputation: 120528
For the purposes of explaining why they all finish at the same time, we can ignore everything except the promise declarations:
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, 'a'); });
const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, 'b'); });
const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, 'c'); });
These promises are created HOT (i.e. the handler passed to the constructor is immediately invoked), and were all created at the same time. It follows that the setTimeout
within will fire in 5 seconds time, no matter how they are subsequently used.
How they are used subsequently is incidental to this, however, to get your example working, it might be better to write functions that return Promise when called... so:
const getPromise1 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 5000, 'a');
});
const getPromise2 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 5000, 'b');
});
const getPromise3 = () => new Promise((resolve, reject) => {
setTimeout(resolve, 5000, 'c');
});
getPromise1().then((val1) => {
console.log(val1);
return getPromise2(); //by returning Promise, you can avoid deep nesting
}).then((val2) => {
console.log(val2);
return getPromise3();
}).then((val3) => {
console.log(val3);
});
In answer to comment, it might be better to have an array of arguments that are used to feed to a Promise-returning function, then to use async/await
to write a function that calls the Promise-returning function in sequence
const getPromise = (v) => new Promise((resolve, reject) => {
setTimeout(resolve, 5000, v);
});
async function run(params) {
for (const p of params) {
const returnVal = await getPromise(p);
console.log(returnVal);
}
}
run(['a', 'b', 'c']);
Upvotes: 6
Reputation: 121
Promises starts immediately after you declare it and the .then()
function is just a "onResolve" event, ie, is called when the promise is resolved.
To do what you want, you'll need to use 5, 10 and 15 seconds timeout.
If you want something that's started only when something call it, look for RxJS. It's a great library that have some useful functions to resolve and chain responses. RxJS creates observables that only starts when something subscribe to it.
Upvotes: 0