Why Does setTimeout Run After Promise.then? Unraveling JavaScript’s Event Loop
This article explains how JavaScript’s single‑threaded model achieves asynchronous behavior through macro‑tasks and micro‑tasks, compares the browser and Node.js event‑loop implementations, and demonstrates the timing differences between setTimeout, setImmediate, and process.nextTick with practical code examples.
Browser Environment
JavaScript runs on a single thread, but it can perform asynchronous operations without blocking the main execution flow by using an event loop and task queues.
There are two kinds of tasks:
Macro‑tasks (Task) : setTimeout, setInterval, setImmediate, I/O, UI rendering, etc.
Micro‑tasks : Promise, process.nextTick, Object.observe, MutationObserver, etc.
Macro‑tasks are placed in the task queue, while micro‑tasks have their own queue that is processed after each macro‑task.
setTimeout(function(){ console.log(4); }, 0);
var promise = new Promise(function(resolve){
console.log(1);
for (var i = 0; i < 10000; i++) {
if (i == 9999) resolve();
}
console.log(2);
}).then(function(){ console.log(5); });
console.log(3);The output is 1 2 3 5 4, showing that the Promise.then micro‑task runs before the setTimeout macro‑task.
The event‑loop proceeds as follows:
Start event‑loop.
Empty the micro‑task queue (execute all micro‑tasks).
Check if any macro‑tasks remain; if so, pick one and execute it.
After each macro‑task, return to step 2 to clear micro‑tasks again.
When both queues are empty, end the current loop iteration.
Node Environment
Node.js also uses an event loop, but its implementation differs because it runs on top of libuv, which abstracts platform‑specific I/O mechanisms (epoll, kqueue, IOCP). The loop consists of several phases:
timers : executes callbacks scheduled by setTimeout and setInterval.
I/O callbacks : runs most I/O callbacks except close, timer, and setImmediate callbacks.
idle, prepare : internal use.
poll : retrieves new I/O events; may block if the queue is empty.
check : executes setImmediate callbacks.
close callbacks : runs callbacks like socket.on('close').
Each phase has its own details; for example, the poll phase will execute timers whose lower‑bound time has been reached, and if the poll queue is empty it will either proceed to check (if a setImmediate is pending) or wait for new I/O.
Example of a file‑read operation:
var fs = require('fs');
fs.readFile('/path/to/file', function(){
// file read callback runs in the poll phase
});When the poll phase finishes and the file‑read callback has been executed, the loop proceeds directly to the check phase, where any pending setImmediate callbacks run.
setImmediate() vs setTimeout()
setImmediatecallbacks are executed in the check phase, while setTimeout callbacks run in the timers phase (or later in poll if the timer has not yet expired). The order therefore depends on how much time has elapsed before the timer phase starts.
setTimeout(function(){ console.log('timeout'); }, 0);
setImmediate(function(){ console.log('immediate'); });On many systems the output is nondeterministic: if at least 1 ms has passed before the timer phase, timeout prints first; otherwise immediate prints first.
process.nextTick()
process.nextTickhas its own queue that is drained after every phase of the event loop, regardless of which phase is currently executing. This makes it run before any other pending I/O or timer callbacks.
Overall, understanding the distinction between macro‑tasks, micro‑tasks, and the specific phases of the Node.js event loop is essential for writing predictable asynchronous JavaScript code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent IMWeb Frontend Team
IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
