Code after a loop runs before the async work finishes
“The job logs "done" and the response is sent, but records are still being written afterwards. Sometimes the totals are zero, errors appear after success, or switching to Promise.all overwhelms the downstream API.”
THE PRINCIPLE
Every loop over async work answers three questions: does order matter, how many may run at once, and what happens when one fails.
FIRST MOVES
- Look for forEach(async ...), .map(async ...) without Promise.all, and reduce with async accumulators.
- Need order or one-at-a-time side effects? Use for...of with await.
- Independent work? await Promise.all(items.map(fn)) to fail fast, or Promise.allSettled to collect partial failures. Promise.all does not cancel the others when one rejects.
- Large or unbounded inputs? Bound concurrency to what the downstream allows (rate limit, pool size), not to the array length.
- Enable @typescript-eslint/no-misused-promises (checksVoidReturn flags async forEach callbacks) and no-floating-promises.
TOOLS: THEN → NOW
forEach or map with async callbacksfor...of with await, or Promise.all / Promise.allSettled over mapped promises
Unbounded Promise.all over thousands of itemsBounded concurrency (p-limit or a small worker pool) sized to the downstream limit
PATTERN SNAPSHOT
orders.forEach(async (o) => { await charge(o); }); // forEach ignores the promises
console.log("done"); // runs first; rejections go unhandled
for (const o of orders) await charge(o); // sequential
await Promise.all(orders.map((o) => charge(o))); // concurrent, rejects on first failure
// Concurrent, at most `limit` in flight: workers drain one shared iterator.
async function forEachLimit<T>(items: T[], limit: number, fn: (item: T) => Promise<void>) {
const queue = items.values();
const worker = async () => { for (const item of queue) await fn(item); };
await Promise.all(Array.from({ length: limit }, worker));
}
await forEachLimit(orders, 5, charge);CLOSE THE AI. EXPLAIN THIS.
When one of 1,000 Promise.all calls rejects, what happens to the other 999, and how would you cap the work at 5 in flight?RELATED SYMPTOMS
SOURCES
Guide reviewed