What strategies exist for handling errors across asynchronous flows?
Five strategies cover almost everything, and choosing between them is the real skill.
Catch at the boundary. Handle the failure where the operation started, not deep in the call chain. The lowest layer reports the failure, and the layer that owns the user experience decides what to do about it.
Time out. Any operation that waits on the network needs a deadline, because a request that never resolves is worse than one that fails quickly. A timeout is usually built by racing the real promise against a timer.
Retry. Some failures are transient, such as a dropped connection or a rate limit, and a retry with a growing delay recovers from them. The important rule is to retry only failures that are worth retrying, and to cap the number of attempts.
Collect partial results. When several independent operations run together and you want all of them, the settled combinator reports each outcome separately so one failure does not discard the successes.
Fail fast where it matters. If the operation cannot continue without one particular result, use the strict combinator so you do not wait for work whose result will be thrown away.
Two things to keep in mind while choosing. The place where you catch determines where the error is visible, so catching too low hides failures and catching too high turns a recoverable problem into a dead request. And whatever you do, a retry loop needs a bound, because an unbounded retry against a failing service is an outage of your own making.