Timers are a minimum delay
When you schedule a timer for a delay, you are asking the runtime to run a callback no sooner than that delay. It is a lower bound, not an exact appointment. The callback joins the task queue once the time passes, but it only runs when the loop reaches it and finishes any current work.
Why a timer can fire late
Several factors push the actual firing later than requested.
- A busy loop running long callbacks delays everything queued behind it.
- Microtask draining happens between tasks and can extend the gap.
- Many timers ready at once run one per loop turn, not all instantly.
So a delay value means at least that long, possibly more.
Io completion callbacks
For io such as network or disk, the runtime registers interest with the operating system and continues. When the operating system signals completion, the runtime queues the corresponding callback as a task. Your code never polls. It simply gets called when data is ready.
Key idea
A timer delay is a minimum wait, and io completes via callbacks the runtime queues once the operating system signals readiness, so actual firing depends on the loop being free.