You have sequenced your timers in "way 1" (they each fire a second apart) and run your timers in parallel in "way 2" so the timers all fire at about the same time. Here's the more detailed explanation:
In "way 1", you create a chain of promises with sequence = sequence.then()
and the setTimeout()
is called from within the sequence. So, timer 2 won't start until after timer 1 fires and so on. You will get each individual timer running truly sequential with each firing about 1 second apart.
In "way 2", you start all the timers at once in your .map()
, so all the timers run in parallel, not in sequence. You are then trying to force them into a sequence with your sequence2 = sequence2.then()
loop, but the async operations were already started in parallel so all this sequential loop doesn't really accomplish anything more than a Promise.all()
would in terms of timing.
If you run each of these two snippets, they will log exactly when the timers fire and you can see the difference between the two.
Here, in a version of "way 1" that logs the time sequence of each timer, you can see the timers firing about 1 second apart:
// way 1
let startTime = Date.now();
function log() {
let args = Array.from(arguments);
// calc time since startTime
let delta = (Date.now() - startTime) / 1000;
args.unshift(delta + ": ");
console.log.apply(console, args);
}
function delay(t, val) {
return new Promise(resolve => {
setTimeout(() => {
log("timer fire");
resolve(val);
}, t);
});
}
// Way 1
let sequence = Promise.resolve();
[1,2,3,4].forEach((val)=> {
sequence = sequence.then(()=> {
return delay(1000, val);
}).then(console.log);
});
sequence.then(() => {
log("all done");
})
Here, in a version of "way 2" that logs the time sequence of each timer, you can see the timers firing at all about the same time:
// way 2
let startTime = Date.now();
function log() {
let args = Array.from(arguments);
// calc time since startTime
let delta = (Date.now() - startTime) / 1000;
args.unshift(delta + ": ");
console.log.apply(console, args);
}
function delay(t, val) {
return new Promise(resolve => {
setTimeout(() => {
log("timer fire");
resolve(val);
}, t);
});
}
//Way 2
let sequence2 = Promise.resolve();
[5,6,7,8].map(val => {
return new delay(1000, val);
}).forEach(promise => {
sequence2 = sequence2.then(() => promise).then(console.log);
});
sequence2.then(() => {
log("all done");
});
When running each snippet, not in particular the time it takes to get to the "all done" message. The first one serializes four one second timers so it takes
about 4 seconds to run. The second one runs all the timers in parallel so it takes about 1 second to run.
Additional explanation:
When you do this:
let arrayOfPromoises = [5,6,7,8].map(val => {
return new Promise(resolve => setTimeout(resolve, 1000, val));
});
That code executes return new Promise(resolve => setTimeout(resolve, 1000, val));
four times in a row, one right after the other with no delays. Since each time that code is execute, it creates a new Promise
object, you end up with an array of four promises.
Now, inside of that code you have this:
new Promise(resolve => setTimeout(resolve, 1000, val));
The Promise executor function (that's what the callback is called that you pass to the Promise constructor) is called IMMEDIATELY. There is no waiting. So, not only have you created four promises, but you've also started four times that are all running at once. These timers are already started. No amount of structuring with your sequence2 = sequence2.then()
loop will change that. The timers are already running.