It's 2026 and a page still fires four APIs at once—one fails and the whole page goes blank. Is that a bug?
Bottom line first: when the same page fetches its data concurrently with Promise.all, if any one API rejects, the whole group fails immediately, and successful results already obtained are discarded along with it. That's the behavior defined by the Promise spec, not a bug. In 2026 project delivery, what really needs deciding is the failure semantics: does this batch of data have to include everything, or is some better than none? For the former, keep Promise.all but add inner fallbacks; for the latter, switching to allSettled is less trouble.
Why one failing API takes down the whole group
Internally, Promise.all only recognizes two signals: if all are fulfilled, it resolves with an array of results; if any one rejects, it rejects immediately and stops waiting for the remaining requests. That semantics is correct for all-or-nothing scenarios, but a lot of first-screen data can actually be shown in a degraded form.
What causes the blank page is often not the semantics itself, but the caller assuming it will always succeed. A user not logged in, API rate limiting, or a downstream service timing out can all make the entire page's data go empty at once, so users see a blank page instead of partial content.
- Short-circuits but doesn't cancel: as soon as any one rejects, it enters the failure branch immediately; other requests already sent are not aborted automatically.
- Successful values are discarded: on reject, the outer scope only gets that one error and cannot access the successful partial data.
- Slower to pinpoint: the error object usually doesn't say which API failed unless you wrap it with your own marker.
- Loading state easily gets stuck: if loading is cleared in then instead of finally, the failure path never clears it.
Comparing four concurrency approaches (experience range)
Rather than memorizing APIs, label each request with its failure semantics first, then choose the aggregation method. The following is organized around common 2026 project usage; the time and rework effort are experience ranges, meant for judging order of magnitude rather than exact promises.
- all with inner catch: fits first-screen parallel requests in a fixed order; few changes, low risk, and for a single page it's common to finish within half a day.
- allSettled with result filtering: fits reporting, aggregated lists, and similar "some results are better than none" scenarios; each result keeps status and reason, failures are traceable, and error reporting is smoother.
- Sequential await one by one: use only when there are dependencies; after converting 3–8 concurrent APIs to serial, total time commonly rises from a few hundred milliseconds to 1–2 seconds (experience range).
- any / race: use for picking one source among many or timeout racing; it appears less often in everyday business pages, and it isn't recommended just to look modern.
Then look at a verifiable comparison in terms of rework cost: all with inner catch is a low-risk small change; the downside is you have to assemble failure reasons yourself. allSettled with post-filtering touches more points, but in exchange failure reasons are preserved and can be counted. For the same page, the regression effort for the two commonly differs by around half a day (experience range).
Define failure semantics first, then choose the approach, then add timeouts
Doing it in the reverse order tends to turn into "wrap every request in its own try/catch," which makes the code harder to maintain.
- Label failure semantics: split the page's concurrent requests into critical and optional, and write that into the API integration doc or comments so both sides agree on the same list during integration.
- Then choose the aggregation method: put critical ones in all with their own fallback values; be careful not to use undefined as the fallback, since later destructuring can easily throw again. Put optional ones in allSettled.
- Unify the error exit: catch only once at the outermost layer for degradation messaging and reporting, so multiple catch layers don't swallow each other and alerts can't tell whether it was an aggregation failure or a single-point failure.
- Add timeouts and cancellation: use AbortController or your request library's signal to add a timeout to each request, preventing one hanging request from making the whole group take forever and leaving the loading state spinning.
Acceptance can be checked against these three items: you can list whether each concurrent request is critical or optional; all four cases — all success, partial failure, total failure, and timeout — have been manually tested; and the regression checklist confirms that blank pages, stuck loading, and repeated error toasts no longer occur.
Delivery site: a rework caused by one 401 taking down the whole page
A homepage needed to fetch four APIs in parallel: recommendations, cart badge, profile, and unread message count. Development had two weeks, and to move fast early on, the team wrote bare Promise.all. After launch, when a logged-out user's unread message count returned 401 and rejected directly, the homepage's entire data block went empty and was reported as "the page is broken." The rework was to move the cart badge and unread count out of all and switch them to allSettled with status filtering, while keeping recommendations and profile in all with their own catch. The change plus regression took roughly half a day to a day extra (experience range), at the cost of delaying another small requirement that cycle, but 401s, rate limiting, and timeouts no longer blank the page.
Another easily overlooked point is crawling: if the main first-screen content depends on this all-or-nothing group of requests, then when the group fails, the server-rendered HTML may be nearly an empty page, which also affects what search engines crawl. Check this against your rendering approach and the search engine's official documentation, make critical content degradable or server-rendered directly, and don't bet everything on one group of requests that must all succeed.
When it applies and when it doesn't
Cases worth changing: page data can be partially displayed, there are more than 3 concurrent APIs, and critical vs. optional can be clearly distinguished. In these scenarios, layering failure semantics usually pays off immediately and regression cost stays manageable.
Cases that don't need a heavy approach: the page calls only one API, or the data must hold together anyway (for example, inventory and price validation before placing an order). Continuing with all plus one catch is enough; forcing allSettled only adds more branches and hurts readability.
- Fits: first-screen multi-API parallelism, aggregated lists, reporting pages, and scenarios where weak network or logged-out state routinely requires degradation.
- Doesn't fit: strongly consistent validation chains, single-API calls, serial flows with strict dependencies, and checkout pages where data completeness can't be compromised.
FAQ
If one fails inside Promise.all, do the other requests keep going?
Yes. all simply stops waiting for them; requests already sent are not canceled automatically. To truly stop the damage, you need to actively abort them with AbortController or your request library's signal.
Should I choose Promise.allSettled or Promise.all?
Look at the failure semantics. If you need all the data, use all with inner fallbacks; if some data is better than none, use allSettled and filter by status afterward.
If I wrap Promise.all in try/catch, can I get the partially successful results?
No. On reject, successful values have already been discarded. To keep partial results, you can only switch to allSettled or wrap each request in its own catch.
What if a mini-program base library or old WebView doesn't support allSettled?
First check the support range against the platform's official documentation. If it truly isn't supported, you can wrap all with inner catch to produce an equivalent effect, or introduce a polyfill as needed.
If your page is still using bare Promise.all to fetch multiple APIs, spend half an hour first labeling each request as critical or optional, then decide whether to switch to allSettled or inner fallbacks, and add timeouts and cancellation. For projects with fewer than 3 concurrent APIs, or where the data must hold together anyway, keep the current setup and add one catch layer; there's no need to refactor just to chase a newer pattern.
-
z-index Is Still Covered After Going Very High: Does Increasing It Further Help in 2026?
Date: Sep 16, 2026 Read: 5
-
It’s 2026. Everyone nodded in requirements review—why are empty states and loading states still being filled in during integration?
Date: Sep 14, 2026 Read: 11
-
CDN refreshed, why are some users still seeing the old page?
Date: Sep 13, 2026 Read: 15
-
When Uni-app ships both a mini program and an app and platform differences keep piling up, where should you start in 2026?
Date: Sep 12, 2026 Read: 19
-
In 2026, is a large Flutter install package the engine's fault or too much bundled in the project?
Date: Sep 11, 2026 Read: 21




