Suspense Mechanism: Promise Throwing, Boundary Catches & Resolution
- Last updated
- Prerequisites:
- React Fiber Reconciler
- JavaScript Promises & Exception handling
- react
- suspense
- promises
- concurrency
- error-boundary
- fiber
Read at your depth
The practical view
React `<Suspense fallback={<Loading />}>` lets components pause rendering while waiting for asynchronous operations. When an async resource (like a Promise via React 19 `use()`, `React.lazy()`, or a data library like Relay) is not ready, the component literally throws the pending Promise. The nearest `<Suspense>` boundary catches the thrown promise, displays the fallback, attaches a listener to the promise, and re-renders the component once the promise resolves.
The same idea in other frameworks
`<Suspense fallback={<Spinner />}><AsyncChild /></Suspense>` catching thrown promises.`@defer (on immediate) { <AsyncChild /> } @loading { <Spinner /> }`.`<Suspense><template #default><AsyncChild /></template><template #fallback><Spinner /></template></Suspense>`.`{#await dataPromise}<Spinner />{:then data}<Child {data} />{/await}`.Legacy vs modern
Throwing Promise Implementation vs React 19 use() Suspense
Raw Suspense libraries throw cached promises; React 19 standardizes this behavior via the `use()` API.
if (status === 'pending') throw promise; // ❌ Manual low-level Suspense cacheconst data不易 = use(promise); // ✅ NEW: Standardized native unwrapping and suspendingInterview gotchas
Context
Tests your understanding of the relationship between Suspense and Error Boundaries.
The mechanical answer
When a Promise rejects, the nearest `<Suspense>` boundary cannot resolve it. React treats the rejected promise as a runtime execution error and bubbles the rejection up the tree until it is caught by the nearest **`<ErrorBoundary>`**. If no Error Boundary exists, the application crashes.
Trap
Suspense boundaries only catch *pending* promises to show fallback loading UI; they do *not* catch rejected promises or errors. Always pair `<Suspense>` with an `<ErrorBoundary>`.
Context
Checks knowledge of React's pure render phase contract during Suspense retries.
The mechanical answer
Because state or context could have changed while the promise was pending in the background, React cannot simply resume from the middle of the suspended component. When the promise resolves (`ping`), React restarts the render pass for that subtree from the Suspense boundary downwards to guarantee complete state consistency across the new render cycle.
Trap
Components suspended under Suspense must remain pure and free from render-phase side effects, as they may be evaluated multiple times before committing.