Have I not always heard that timeout-based callbacks always run at or after the timeout, but never before?
“Do this {} at least Xms from now”, right?
Yeah, exactly. Timeout based callbacks register a timer with the runtime, and when the timer is up, then the callback gets added to the end of the task queue (so once the timeout is up, you've got to wait for the current loop iteration to finish executing before your callback gets executed).
this has always been my understanding as well - it schedules a function to run at time, but it won't pre-empt something that is blocking when it needs to run so there's always the possibility that it has to wait for another function to finish before it can run - a timeout is not a guarantee.
I always kinda figured that any "timer" in any language would technically need to work that way unless you're running a very fancy real-time system because multitasking, especially in high load scenarios, means there just may not be clock cycles available for your task at the exact millisecond you set something to execute at.
So it is with JS; I kinda figured EVERYTHING would need to be heavily throttled in a browser in order to respect the device running that browser.
Sure, but the nuance here is there is a (otherwise usable) range of values for which the timers are only ever "after" instead of "at or after". I.e. the lower bound is artificially increased while the upper bound remains unlimited.