Why does while loop runs before setTimeout? [duplicate]

I am new to Javascript, and recently got to know the use of setTimeout set to 0 millis. I am trying to implement it but not getting what is expected. As per my knowledge it has to wait until all events finished but it is not behaving expectely. Please tell me what I am missing or where I am wrong.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test HTML</title>

</head>
<body>

    <script src="js/index.js"></script>
</body>
</html>

index.js

(function(){

    setTimeout(function () {
        document.write("<p>Event 0 Processed !!</p>");
    },0);

    setTimeout(function () {
        document.write("<p>Event 1 Processed !!</p>");
    },1000);

    setTimeout(function () {
        document.write("<p>Event 2 Processed !!</p>");
    },2000);

    setTimeout(function () {
        document.write("<p>Event 3 Processed !!</p>");
    },3000);

})();

output

Event 0 Processed !!

Event 1 Processed !!

Event 2 Processed !!

Event 3 Processed !!

I was expecting something like

Event 1 Processed !!

Event 2 Processed !!

Event 3 Processed !!

Event 0 Processed !!

Thanks :)


Solution 1:

setTimeout with a delay of 0 waits for the current call stack to clear, not the event queue. The other timeouts all enqueue a callback, so they are not part of the call stack.

If you were to immediately call a logging function, the 0 timeout would wait for that to complete, but not other timeouts. For example:

function log(n) {
  console.log("Event", n, "processed!");
}

setTimeout(log.bind(null, 0), 500); // wait 0.5 seconds
setTimeout(log.bind(null, 1), 0); // wait until the stack clears
log(2); // run now

As MDN explains it:

even though setTimeout was called with a delay of zero, it's placed on a queue and scheduled to run at the next opportunity, not immediately. Currently executing code must complete before functions on the queue are executed, the resulting execution order may not be as expected.

As Jeremy Starcher mentioned in their deleted answer, a delay of 0 is a soft 0ms. It will put the callback to the top of the queue, but provides no guarantee that it will actually be run immediately. The current context must exit, which could be immediate or never occur. On top of that, browsers only check the queue for pending callbacks occasionally, so the implementation may introduce an extra delay.