For a fair comparison, you would want to place the console.log within the resolve like this
for( var i = 0; i < 5; i++) {
new Promise((resolve, reject) => {
resolve(console.log(i));
});
}
Still, this would yield the same results because there is no async delay. But then why does a setTimeout that has 0 delay not produce the same result?
NodeJS has a first in last out callstack, with each cycle referred to as a tick. When a setTimeout resolves, it gets placed in the message queue, which doesn't run until the next tick. When a promise resolves, it gets to cut back in line immediately within the current tick.
The call stacks therefor look like
setTimeout:
timeout i ++ > timeout > i ++ > timeout > i ++ > timeout > i ++ > timeout > i ++ > log > log > log > log > log
promise:
promise > resolve > log > i++ > promise > resolve > log > i++ > promise > resolve > log > i++ > promise > resolve > log > i++ > promise > resolve > log > i++
So you can see that by the time the console.logs within setTimeout are called, i has already been equated to 5, where as the promise console.logs get to cut back in line before i is iterated.
for( var i = 0; i < 5; i++) {
setTimeout( ()=> {
console.log("setTimeout:",i);
});
}
for( var i = 0; i < 5; i++) {
new Promise((resolve, reject) => {
resolve(console.log("Promise:",i));
});
}
Also notice that the Promise console.logs occur before setTimeout console.logs even though the setTimeout loop occurs first. This shows the current tick includes both for loops, so any setTimeout console.log has to wait until they both complete.