Skip to content

Async

Everything at once

Mapping over a list with Promise.all, and what happens when the list is longer than the thing at the other end can take.

12 minutes · backpressure · concurrency limits · semaphores

Promise.all is not a loop

await Promise.all(items.map(handle)) starts every one of them immediately. With four items that is fine. With four thousand it is a self-inflicted denial of service on whatever is at the other end, and the failure arrives as rate-limit errors or timeouts that look like somebody else's fault.

The fix is a limit, and a limit is a semaphore: a fixed number of permits, taken before the work and given back after. What makes it interesting is that the limit has to hold across every concurrent caller, which means the counting has to be right under interleaving.