Event Loop
In short
The event loop is a mechanism that lets a single thread handle many tasks by running callbacks one at a time as events and I/O results become ready.
What is the event loop?
The event loop is the part of a runtime that decides which piece of code runs next. In JavaScript, both in browsers and in Node.js, your code runs on a single main thread, so only one piece of JavaScript executes at a time. Instead of waiting for slow operations like network requests, timers, or file reads, the runtime starts them in the background, and the event loop runs the matching callback once the result is ready.
It works together with a call stack and task queues. The call stack holds the functions that are currently running; when it is empty, the event loop first runs every pending microtask, such as resolved promise callbacks and code after an await, and then takes the next task, sometimes called a macrotask, such as a setTimeout callback or an incoming network event. In Node.js the loop cycles through fixed phases for timers, I/O callbacks, and setImmediate, and a library called libuv handles the waiting underneath.
Picture a single chef who starts the pasta boiling, sets a timer, and chops vegetables while waiting, reacting to each timer as it goes off instead of staring at the pot. This design is why a Node.js server can handle thousands of concurrent connections with one thread and why browsers stay responsive while waiting for data. Similar loops power Python's asyncio, desktop GUI toolkits, and game engines.
The event loop is often misunderstood as running JavaScript in parallel. It provides concurrency, meaning many tasks make progress by taking turns, not parallelism, meaning tasks running at the same instant on different CPU cores. A long synchronous task, such as a huge loop or parsing a giant JSON file, blocks the loop, so timers fire late and a server stops responding until it finishes, which is why such work should be split up or moved to worker threads.
At a glance
Key takeaways
- The event loop runs callbacks one at a time on a single thread.
- Slow I/O happens in the background, so the thread never sits idle waiting.
- Microtasks, like promise callbacks, run before the next task, like a
setTimeoutcallback. - It provides concurrency, not parallelism.
- Long synchronous code blocks the loop and freezes everything else.
Example
console.log("1: synchronous code runs first");
setTimeout(() => console.log("4: timer callback (a task)"), 0);
Promise.resolve().then(() => console.log("3: promise callback (a microtask)"));
console.log("2: still synchronous");
// Output order: 1, 2, 3, 4
// Even a 0 ms timer waits until the call stack is empty
// and every pending microtask has run.Readers ask
Is JavaScript single-threaded?
JavaScript code runs on a single main thread, and the event loop schedules everything that runs on it. The runtime itself uses other threads for work like networking and file I/O, and you can create more with web workers in browsers or worker_threads in Node.js.
What is the difference between microtasks and macrotasks?
Microtasks, such as promise callbacks and queueMicrotask(), run as soon as the current code finishes, and all of them run before anything else. Macrotasks, such as setTimeout, setInterval, and I/O callbacks, run one per turn of the event loop, after the microtask queue is empty.
What does blocking the event loop mean?
It means running synchronous code that takes so long that the event loop can't process anything else, such as incoming requests, timers, or clicks. Break the work into smaller pieces, use asynchronous APIs, or move it to a worker thread.
See also
- Node.jsBackend & APIs, p. 32Node.js is an open-source JavaScript runtime that runs JavaScript outside the browser, most often to build web servers, APIs, and command-line tools.
- JavaScriptWeb Development, p. 24JavaScript is the programming language that runs in web browsers to make pages interactive, and it also runs on servers through runtimes like Node.js.
- Async/AwaitProgramming Fundamentals, p. 4Async/await is a syntax for writing asynchronous code that reads like ordinary step-by-step code, pausing at each await until a promise or task finishes.
- PromiseProgramming Fundamentals, p. 46A promise is an object that represents the eventual result of an asynchronous operation, letting code react to success or failure once the work completes.
- CallbackProgramming Fundamentals, p. 7A callback is a function passed as an argument to another function, which then calls it later, for example when a task finishes or an event happens.
- ConcurrencyProgramming Fundamentals, p. 12Concurrency is a program's ability to make progress on several tasks in overlapping time periods, such as serving many users at once rather than one at a time.
- Web WorkerWeb Development, p. 58A web worker is a browser feature that runs JavaScript on a background thread, so heavy computations don't freeze the page's user interface while they run.
Sources
Spotted a mistake or something missing on this page?Suggest an edit