Waiting and blocking are different
On the frontend, a long JavaScript calculation freezes interactions. A long calculation in Node can delay unrelated users' requests.
JavaScript callbacks in one Node process generally execute on one main thread. Node coordinates asynchronous operations through its event loop and other runtime facilities. Waiting for a database response does not require JavaScript to repeatedly check whether the result has arrived.
Consider this illustrative route operation:
const task = await readTaskFromPostgres();
return task;
The database driver submits work over a network connection. When the function reaches await, it suspends that function. The process can handle other ready work while PostgreSQL processes the query.
await does not move arbitrary JavaScript calculations to another thread. The following code still occupies the JavaScript thread:
// Illustrative CPU work. Async syntax does not make it non-blocking.
async function expensiveCalculation() {
for (let i = 0; i < 100_000_000; i++) {
Math.sqrt(i);
}
}
Slow work has different causes
A slow query can make a request slow without keeping JavaScript busy throughout the wait. A large synchronous calculation can delay every callback in the process. Both need attention, but their fixes differ.
An index or a better query can reduce database work. CPU-heavy work may need a worker thread, another service, or a bounded background operation. Adding async to its function signature does not solve it.
Taskboard uses a separate process for durable background jobs. Email delivery should not make the invitation HTTP response wait for an SMTP server. The database records the job, and the worker handles delivery later.
That separation does not remove all resource limits. A worker can overload the email provider. An API can open too many database queries. Concurrency needs limits even when each operation uses await.
A common mistake is starting every operation with Promise.all over an unbounded list. Ten thousand asynchronous queries still demand connections and database capacity. Asynchronous means that waiting can overlap. It does not mean that resources are unlimited.
Does awaiting a database query stop all requests?
No. It suspends the current function. Other callbacks can run while the query is pending, unless some code blocks the JavaScript thread.
Distinguish time spent waiting for another system from time spent executing JavaScript. That distinction guides performance investigations.
Read api/src/db.ts Read api/src/worker-main.ts