Today I tried out what happens when I add multiple chains of then to a Promise. My test code looks like that (TypeScript)
class Test {
private simulateHeavyStuff(time: number){
// console.log("-"+time+"-");
var start = new Date().getTime();
var end = start;
while(end < start + time) {
end = new Date().getTime();
}
}
test(): Promise<void> {
let promise = new Promise<void>((resolve, reject) => {
resolve();
});
// ##### ADDING CHAIN 1 #####
promise
.then(()=>console.log("then1"))
.then(()=>this.simulateHeavyStuff(2000))
.then(()=>console.log("then11"))
.catch(console.error)
return promise;
}
}
let t = new Test();
// ##### ADDING CHAIN 2 #####
t.test()
.then(()=>console.log("then2"))
.then(()=>console.log("then21"))
.catch(console.error)
This prints out:
then1
then2
<---it's pausing here
then21
then11
Can someone explain the determinism behind this behavior?
I thought it would either print (parallel chains)
then1
then2
then21
<--- I guessed the pause will be here
then11
or (one chain)
then1
<--- with the pause here
then11
then2
then21
OK, I guess I understand what happens after some clarifications of Jaromanda X down in the comments!
It is fully deterministic!
Promises add the callbacks to the so called "Microtasks" stack. Other than other JS stacks those Microtasks run when the JS stack is empty (all synchronous code is done)...see the Video posted by Jaromanda X in the comments!
So it happens like this:
Synchronous code is done! Microtasks time!
The MT Stack looks like this now
then1
then2
So then1 is run and adds another Microtask to the MT stack as it returns a Promise. The MT stack looks like this now
then2
heavyStuff(2000)
As further Microtasks are run until the MT stack is empty this goes on until all MTs are finished. Then any other code goes on...