A fast server can still leave a web request waiting
Network trips, queues, and browser work can outweigh a tiny handler.
A web request can feel slow because executing server code is only one part of the visitor’s wait. Connection setup, network travel, queues, downstream services, and the browser’s final display work can each take longer than the handler itself.
Start by checking what your timer actually measures: a timer inside a route misses anything that happened before that route began. Google’s Time to First Byte guide includes redirects, DNS lookup, connection setup, and waiting for the response in the navigation interval. A five-millisecond handler and a much longer browser measurement can both be correct because their clocks cover different parts of the journey.
Dependent requests add repeated travel, even when each server does little work. In a hypothetical example with an established connection, an 80-millisecond round trip, tiny responses, and three sequential five-millisecond handlers, the chain takes about 255 milliseconds. Reducing every handler to one millisecond saves 12 milliseconds; removing one dependency saves about 85 milliseconds under those same assumptions, making request order a potentially larger opportunity than faster code.
Waiting can also happen beside an otherwise fast handler when another request holds a shared resource. Node.js explains that a long callback can prevent other clients from getting their turn on the event loop. An asynchronous database call lets other work proceed while it waits, but it cannot make the database answer sooner, and low CPU use cannot rule out a shortage of available database connections.
Receiving the bytes still does not mean the page has shown its result. Google’s Largest Contentful Paint guide describes cases where an image finishes downloading but remains hidden until JavaScript completes, so a smaller image fails to advance the visible result. Compare connection setup, response waiting, download time, and the delay before display, then match browser and server records for the same slow request.
Choose the next optimization by finding the largest unexplained wait on a slow visitor’s path and measuring through the visible update.
Sources3
- 1Time to First Byte (TTFB)web.dev
- 2Don’t Block the Event Loop (or the Worker Pool)nodejs.org
- 3Optimize Largest Contentful Paintweb.dev