Fullstack CourseLearn by building
Back to week 1

Topic

Node.js async work & the event loop

Definition

The Node.js event loop coordinates JavaScript callbacks and promise continuations while asynchronous I/O is performed by the operating system or Node worker pool, allowing one process to keep many operations in flight without blocking on each one.

In simpler words

Node can start I/O, work on other requests, and continue when the result is ready — but slow synchronous work still blocks every request sharing that process.

HTTP handlers, database calls, password hashing, and file operations are asynchronous. Understanding await, rejection, and blocking work prevents framework code from hiding runtime-level failures.

After this you can

  • Explain what async/await does and does not make asynchronous
  • Distinguish non-blocking I/O from CPU-heavy synchronous work
  • Propagate rejected promises to an HTTP error boundary
  • Avoid fire-and-forget work that loses errors

Promises and async/await

Definition

A Promise represents the eventual fulfillment or rejection of an asynchronous operation; an async function always returns a Promise, and await pauses only that function until the Promise settles.

In simpler words

await makes promise code read in order. It does not freeze Node, but it also does not turn synchronous CPU work into background work.

Returning or awaiting a Promise keeps success and failure connected to the caller.

Independent operations may run concurrently with Promise.all; dependent operations should remain sequential.

Catch an error only when you can add context, recover, or translate it. Otherwise let the framework error boundary handle it.

Keep failures connected to the request

app.get('/notes/:id', async (req, res, next) => {
  try {
    const note = await notes.findById(req.params.id);
    res.json(note);
  } catch (error) {
    next(error);
  }
});

Awaiting the repository call lets the handler pass rejection to Express error middleware. Nest later performs this translation through its request pipeline and exception filters.

Mistake: detached work

// Wrong — rejection is detached from the request
app.post('/notes', (req, res) => {
  notes.save(req.body);
  res.status(201).end();
});

// Right — await before claiming success
app.post('/notes', async (req, res, next) => {
  try {
    const note = await notes.save(req.body);
    res.status(201).json(note);
  } catch (error) {
    next(error);
  }
});

Do not report success before the write has succeeded unless an explicit durable background-job design exists.

Blocking the event loop

Definition

Event-loop blocking occurs when long synchronous JavaScript or synchronous native work prevents Node from starting or completing other callbacks in the same process.

In simpler words

One expensive synchronous task can stall every request handled by that process.

Synchronous file reads, huge JSON transformations, unbounded loops, and inappropriate password-hashing settings can delay unrelated requests.

Prefer asynchronous I/O APIs. For truly CPU-heavy work, use bounded worker threads or a background-job system.

Measure before optimizing: latency, event-loop delay, and CPU profiles identify whether the bottleneck is I/O, the database, or CPU work.

Keep in mind

  • Return or await every request-scoped Promise.
  • Do not send a success response before the required write succeeds.
  • Treat synchronous CPU work as shared latency for every request in the process.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥ 80% (enforced by the API) to save progress.

Checking your session…

10 questions · concept 3 · syntax 2 · practical 3 · logic 2

Concept1. Which statement best defines Node.js async work and the event loop?
Syntax2. Which code-level choice matches Node.js async work and the event loop?
Practical3. A reviewer spots a bug related to Node.js async work and the event loop. What is the right fix?
Logic4. Which reasoning correctly explains Node.js async work and the event loop?
Concept5. Which boundary does correct use of Node.js async work and the event loop preserve?
Practical6. What is the safest next step when applying Node.js async work and the event loop?
Syntax7. Which implementation direction matches the rule for Node.js async work and the event loop?
Logic8. Which consequence follows from applying Node.js async work and the event loop correctly?
Concept9. Which claim about Node.js async work and the event loop is true in this Nest + Postgres monorepo?
Practical10. Which team practice best demonstrates Node.js async work and the event loop?