I came across some code that uses setTimeout
to make sure that a callback is executed after the document has been parsed.
For example:
<!DOCTYPE html>
<html>
<head>
<script>
setTimeout(() => console.log(document.readyState));
</script>
</head>
<body>
<!-- lots of HTML to parse, which will take a long time -->
</body>
</html>
Here the HTML is parsed first and then the document readyState of complete
is logged in the console.
My guess is that the parsing appears in the call stack before the callback or something like that, but I don't understand how this works. I expected that there would be a race between the parsing and the callback to finish first.
Why is the callback executed after the document has been parsed?
Because setTimeout
is essentially an asynchronous operation. Even with no actual timeout specified (defaulting to 0), it doesn't immediately execute. It adds the task to a "list of things to do later". When the current operation (executing the initial inline code while rendering the page) is complete, the event loop moves on to whatever is next on that list.
It can't pre-empt the current operation, only blocking operations can do that because they are effectively part of the current operation. Anything that gets added to the event loop will be processed later.
As an aside, this is also why things like setTimeout
and setInterval
are not 100% accurate. As your code accidentally demonstrates, the timeout was actually longer than 0. You could also set a timeout of something like 1000 and then immediately afterward have a blocking loop that takes several seconds to process. Despite the 1-second timer, the event loop can't get around to that operation until after the several-second blocking operation completes.