Frontend Development 17 min read

Why JavaScript Has an Event Loop: Origins and Browser vs Node.js Differences

This article explores the historical reasons behind JavaScript's event loop, explains the task and microtask queues, compares browser and Node.js implementations, and provides concrete code examples to illustrate how tasks are scheduled and executed across environments.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
Why JavaScript Has an Event Loop: Origins and Browser vs Node.js Differences

Why There Is an Event Loop

JavaScript was created by Netscape for richer web interactions; its original design did not include an event loop. The loop appeared later to let user agents (browsers) coordinate events, scripts, rendering, networking, and more, as defined in the HTML specification.

To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section.

Thus the event loop is a mechanism used by the user agent, not a language feature of JavaScript itself.

What the Event Loop Is

From a developer's perspective the event loop consists of two queues:

Task Queue (external queue) : handles DOM operations, user interaction, network requests, History API actions, timers, etc.

Microtask Queue (internal queue) : handles Promise callbacks, MutationObserver, and the now‑deprecated Object.observe.

Although called queues, they behave more like ordered sets; a task is only taken when its conditions are satisfied.

Processing Model

Take one executable task from the external queue and run it.

Execute all tasks in the microtask queue.

Render the page.

Example Analysis

Consider the following code:

<code>console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');</code>

Output:

<code>script start
script end
promise1
promise2
setTimeout</code>

Processing steps:

Execute

console.log('script start')

.

Enqueue the

setTimeout

callback in the external queue.

Enqueue the two Promise callbacks in the microtask queue.

Execute

console.log('script end')

.

Run all microtasks (promise1, promise2).

Run the external task (setTimeout).

Browser vs Node.js Event Loop Differences

In browsers the event loop includes HTML rendering and limits each cycle to a single external task, while Node.js integrates JavaScript into libuv’s I/O loop, allowing multiple external tasks per cycle.

Key differences:

Node.js has no HTML rendering phase.

External task sources differ: browsers handle user input; Node.js handles file and network I/O.

Node.js historically allowed multiple external tasks before processing microtasks, unlike browsers.

Example showing the historic Node.js behavior:

<code>setTimeout(() => {
  console.log('timer1');
  Promise.resolve().then(() => console.log('promise1'));
});

setTimeout(() => {
  console.log('timer2');
  Promise.resolve().then(() => console.log('promise2'));
});</code>

Browser output: timer1 → promise1 → timer2 → promise2.

Node.js (pre‑v11) output: timer1 → timer2 → promise1 → promise2.

Node.js introduced

setImmediate

as a separate external queue with higher priority than

setTimeout

:

<code>setTimeout(() => {
  console.log('setTimeout1');
  Promise.resolve().then(() => console.log('promise1'));
});

setImmediate(() => {
  console.log('setImmediate1');
  Promise.resolve().then(() => console.log('promise3'));
});</code>

Result on Node.js 10.x:

<code>setImmediate1
setImmediate2
promise3
promise4
setTimeout1
setTimeout2
promise1
promise2</code>

Node.js’s event loop consists of several phases (timers, pending callbacks, poll, check, close) each with its own external queue; the

check

phase runs

setImmediate

callbacks.

Summary

The event loop is a coordination mechanism provided by the host environment (browser or Node.js) to interleave user interactions, script execution, rendering, and I/O. Understanding the distinction between external (task) and internal (microtask) queues clarifies why promises run before timers and why browser and Node.js implementations differ.

JavaScriptNode.jsbrowserasyncevent-loopMicrotasktask queue
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.