First off setTimeout() is asynchronous and non-blocking. That means when you call it, all it does is register the new timer and then immediately returns. So, when your code runs, it will follow these steps:
- You register the
func1 timer for 500ms.
- You register the
func2 timer for 250ms.
- Each of the timers is added to a sorted data structure inside the timer portion of the event loop so it's easy for the event loop to know and check which timer is next to execute.
- You start the
while spin loop. That loop runs for about 1000ms.
- When the
while spin loop finishes, the Javascript interpreter gets to go back to the event loop to check if there is anything else to do. One of the things it checks (one of the phases of the event loop) is to see if there are any timers ready to run. It checks the head of the timer list and sees that its time has already passed by (meaning it is past time for it to run). So, it grabs the callback associated with that func2 timer and executes it. The func2 timer is at the start of the list because it's has the earliest time associated with it.
- When that callback finishes executing, the JS interpreter again returns control back to the event loop where it again checks if there isn't anything else to do. It will find that the func1 timer is now at the head of the list and past its time to run so it grabs the callback associated with that timer and executes it.
And thus, you get the output you see with the func2 callback executing as soon as the while spin loop is done, then the func1 callback executing after that.
Note, these timers are purely event driven. There is no interrupting of the currently executing Javascript to execute a timer. For this reason, timers in Javascript are a best effort kind of implementation. If you set a timer for 1000ms from now, then the callback associated with that timer will run no sooner than 1000ms and could be later than that if the JS interpreter was busy at the appointed time for that timer.
The one aspect of timers that is missing from the above description (because it doesn't occur in your situation) is what happens if you don't have the while() spin loop. In that case, your code returns control back to the event loop right after configuring both timers, the event loop checks to see if any timers are ready to run, but none are yet ready to run. It will then sleep until something wakes it up again, but not sleep longer than the time to the next currently set timer.