The line setTimeout(function () { console.log('Yo!'); }, 1000); will result in creating a timer for 1000ms using the browser API, which will later add the callback function into what is called a callback queue after 1000ms have passed by(this will happen somewhere in the future). However this does not mean that the thread of execution will stop executing the rest of the code. (Since JS in single threaded the browser will handle the waiting part and JS will continue on executing)
while (Date.now() < start + 3000) {} When the thread of execution reaches this line, it will keep checking the condition until it becomes false that means there is no waiting done by the browser API but the thread of execution will keep running the loop for 3 seconds. Somewhere during these 3 seconds the browser API's timer set with the setTimeout function will complete (in approximately 1000ms) and add the function definition of the anonymous function(callback) into the callback queue(This means the countdown of 1000ms has already been completed).
Note: Just because some code that is ready for execution is in the callback queue does not mean it will be executed immediately. It will need to pass two conditions(there are more, but only 2 will be applicable here) to be added to the main call stack which are checked by the event loop. The conditions are:
- Call stack must be empty (no functions are currently running)
- No more synchronous code left for execution
so in the question provided,
while (Date.now() < start + 3000) {}
console.log('After wait');
both these lines are synchronous code, thus will complete execution before console.log('Yo!'); is added to the call stack and executed.
To sum up the reason "Yo!" is logged immediately after "After wait" is because the two wait times are happening in parallel (with the help of the browser as JS is single threaded)
References: https://www.youtube.com/watch?v=i9lNaTQ6n9c