JavaScript runs one call stack. When it empties, all queued microtasks (promise callbacks) run, then one macrotask (timer, I/O), then microtasks again.
console.log(1); setTimeout(() => console.log(3)); Promise.resolve().then(() => console.log(2)); // 1, 2, 3
A long synchronous loop blocks rendering and every timer — chunk heavy work or move it to a worker.