One waiter, many tables
A smart waiter: A good waiter doesn't stand at the kitchen waiting for one order. They take an order, hand it to the kitchen, serve another table, and come back when the food's ready. Node's single thread works the same way: it never waits — it registers a callback and moves on. That's the event loop.
Order of execution
console.log("1. synchronous code runs first");
setTimeout(() => console.log("4. timer callback"), 0);
Promise.resolve().then(() => console.log("3. promise callback (microtask)"));
console.log("2. still synchronous");- Never block the loop: a long synchronous loop freezes *every* request on the server.
- process.nextTick(fn) is a Node-only queue that runs even before promise callbacks — rarely needed in app code.
- Run independent async work in parallel with Promise.all([a(), b()]) — not one after another.
- Heavy CPU work (image processing, big calculations) belongs in worker threads or a separate service.
const wait = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
const t1 = Date.now();
await wait(100, "a");
await wait(100, "b");
console.log("one after another:", Date.now() - t1 >= 200 ? "~200ms" : "?");
const t2 = Date.now();
const [a, b] = await Promise.all([wait(100, "a"), wait(100, "b")]);
console.log("in parallel:", a, b, Date.now() - t2 < 180 ? "~100ms" : "?");