Cache: don't recompute what you already know
If an operation is expensive (a heavy query, an external call) and its result changes little, cache it. An in-memory store like Redis keeps key-value pairs with near-instant access and an optional TTL (time to live):
// Conceptual pseudocode:
let data = await redis.get("user:1");
if (!data) { // "miss": it was not in the cache
data = await db.findUser(1);
await redis.set("user:1", data, "EX", 60); // expires in 60 s
}
The cache-aside pattern: check the cache first; if there is a hit, return it; if there is a miss, compute, store in the cache and return.
Use all the cores
A Node process uses one core for your JS. To take advantage of a machine with several cores there are two complementary tools:
- Clustering (
node:cluster): launches several identical processes (workers) that share the same port. The system distributes the incoming connections among them. It solves the scaling of an HTTP server: more processes serve more requests in parallel, and if one goes down, the others keep going. worker_threads: threads within a process, with their own event loop. They are useful for CPU-intensive work (processing images, heavy calculations) without blocking the main thread.
Don't block the event loop
Since your JS is single-threaded, a long synchronous operation freezes EVERYTHING: while it computes, no other request is served.
// BAD: blocks the event loop during the whole loop.
function slowSum(n) {
let total = 0;
for (let i = 0; i < n; i++) total += i; // if n is huge, nobody else advances
return total;
}
The golden rule: keep the main thread free. Heavy CPU work goes to
a worker_thread; I/O (network, disk, DB) is already asynchronous and does not block. That way the
event loop keeps accepting and responding to requests.
Examples
Cache-aside: a hit avoids recomputing
const cache = new Map();
function getExpensive(key, compute) {
if (cache.has(key)) return cache.get(key); // hit
const value = compute(); // miss: compute
cache.set(key, value); // and store
return value;
}
let times = 0;
const calc = () => { times++; return 42; };
getExpensive("x", calc);
getExpensive("x", calc); // second time: hit, does not recompute
console.log(times); // 1