Async/await makes asynchronous code look synchronous, which is exactly when authors forget the difference. A missing await produces a Promise where a value was expected — sometimes silently, when downstream code doesn't care; sometimes loudly, when .then() fires after the response was already sent.

The mirror image is over-awaiting: serializing two requests that should fire in parallel, doubling latency for no reason. Both bugs come from the same root cause — the linear shape of async code hides the actual control flow.

Tools help. Strict TypeScript flags no-floating-promises, runtime trace tools attribute unhandled rejections to a source, and Promise.all forces you to think about parallelism explicitly. But the human review pattern is to read every async function asking: which awaits are necessary for correctness, and which awaits should have been skipped to keep concurrency?

Review heuristic

Read every async function twice: once for missing awaits, once for unnecessary awaits. The first set causes incorrectness; the second set causes performance regressions that nobody notices until the API gets slow.