The Event Loop and Concurrency Model
Prerequisites: Async/await
JavaScript runs on a single thread — only one piece of code executes at a time. Long-running operations (a network request, a timer) don't block that thread; instead, they're handed off, and their callback is queued to run later via the event loop.
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// Output: 1, 4, 3, 2
Even with a 0ms delay, setTimeout's callback runs after the
currently-executing code finishes, and Promise callbacks
("microtasks") run before setTimeout callbacks ("macrotasks"). This
single-threaded model is why JavaScript never needs Python-style
threads/locks for basic async work — but it also means one long,
blocking, synchronous computation freezes everything else, including
the browser's UI.