How Node.js handles 10,000 connections with a single thread.
Most languages use multi-threading: 1 request = 1 OS thread. But threads consume lots of RAM. Node.js (and Python Asyncio) use a Single-Threaded Event Loop. The single thread acts like a fast waiter in a restaurant. It takes your order (an HTTP request), hands it to the kitchen (the Database), and instead of standing there waiting, it immediately walks over to the next table to take another order. When the kitchen is done, it puts the result in a "Task Queue", and the waiter delivers it when they have a free moment.
This only works if the waiter NEVER does the cooking themselves. Whenever you do network I/O, you must use await or a callback. This tells the runtime: "I am pausing this function. Go run other code in the Event Loop, and wake me up when the network responds."
# Node.js Event Loop Example
app.get('/user', async (req, res) => {
// 1. Thread executes this line instantly
console.log("Fetching user...");
// 2. AWAIT: The thread pauses this function, hands the query to the OS,
// and goes to serve other users! It is NOT blocked here.
const user = await db.query("SELECT * FROM users");
// 3. (Milliseconds later) The DB responds. The OS puts this function
// back in the Task Queue. The Event Loop picks it up and resumes here.
res.json(user);
});
Event loops provide incredible concurrency for I/O bound apps (web servers) using virtually zero RAM compared to OS threads. However, if you run a CPU-heavy task (like image processing or a massive for loop) on the main thread, the waiter is "stuck cooking". The event loop is blocked, and no other users can be served until the math finishes.
fs.readFileSync() instead of fs.readFile() in Node.js forces the event loop to stop and wait for the hard drive. A single synchronous file read in a web endpoint will destroy the server's throughput.