Defensible by designDecisions remain reviewable and evidenced.
Transparent processScope, ownership and boundaries stay visible.
Client-first partnershipWork starts with the operating need.
Secure by defaultAccess and sensitive data stay controlled.
Beyond ZeroAuthority lesson35–45 minutes

JavaScript Beyond Zero · Lesson 06 of 14

Promises, Fetch, Cancellation, and Race Control

Understand where Promises, Fetch, Cancellation, and Race Control fits in a maintainable, testable, and reviewable engineering workflow.

Design asynchronous browser work around ownership, stale results, cancellation, and explicit request state rather than assuming promise order matches user intent.

This public lesson does not reproduce the complete manuscript.

Authority lesson · 866 words

Promises, Fetch, Cancellation, and Race Control

A promise settles once, but user intent keeps changing

When a user types, changes filters, navigates, or resubmits, multiple requests can overlap. The network may return them out of order. If every response updates the interface, an older result can overwrite the newer choice. The defect is not that promises are unreliable; it is that the application did not define which operation owns the visible state. Give each request an identity or generation and apply a result only when it still represents current intent.

Keep request state explicit: idle, loading, successful, empty, failed, or cancelled. Do not infer loading from missing data. Separate previously displayed data from the request in progress so the interface can choose whether to retain it, mark it stale, or clear it. This makes accessibility messages and tests deterministic.

Cancellation is resource and intent control

AbortController lets an application signal that a fetch is no longer needed. Abort when a component is removed, a newer search supersedes the old one, or a deadline expires. Treat AbortError as a distinct outcome rather than showing a failure message. Cancellation may not stop the server after the request has arrived, so server operations still need idempotency and authorization.

Pass the signal through every adapter that performs work. Clean up timers and event listeners. Do not create one global controller for unrelated requests. Ownership should follow the feature instance or operation. If several requests form one operation, decide whether one cancellation stops all of them or only a branch.

Fetch success is not HTTP success

Fetch rejects for network failures, not for ordinary 4xx or 5xx responses. Check response status and parse content according to its type. Handle empty responses and invalid JSON. Bound body size where possible and avoid inserting untrusted text with innerHTML. Translate transport details into domain results such as validation_error, unauthorised, temporarily_unavailable, or invalid_response.

Use deadlines and retries carefully. Retrying a safe GET may be reasonable for selected temporary failures. Retrying a POST can duplicate work unless the server supports idempotency. Respect rate-limit guidance and add jitter. The browser should not create a retry storm when the service is overloaded.

Test ordering and accessibility

Write tests that resolve requests in reverse order, cancel during navigation, return 404 and 500 responses, provide malformed JSON, and simulate slow networks. Verify that stale results are ignored, controls are re-enabled, focus is not stolen, and status messages are announced appropriately. A spinner without accessible status can leave keyboard and screen-reader users uncertain whether anything happened.

Instrument request duration, cancellation, error category, and zero-result outcomes without capturing private query content unnecessarily. Operational evidence helps distinguish slow APIs, client race defects, and users refining a search. Keep analytics subordinate to privacy and the actual product decision.

Release review for promises fetch cancellation and race control should name an owner, evidence location, review date, and the exact condition that would trigger a different decision. That record keeps the lesson tied to operational responsibility rather than leaving it as general advice. Teams should revisit the choice after incidents, major dependency changes, new data classes, or a material increase in scale.

Release review for promises fetch cancellation and race control should name an owner, evidence location, review date, and the exact condition that would trigger a different decision. That record keeps the lesson tied to operational responsibility rather than leaving it as general advice. Teams should revisit the choice after incidents, major dependency changes, new data classes, or a material increase in scale.

Scenario

A search box shows results for the previous query

A visitor types “python”, then quickly changes to “python testing”. The second request returns first, but the slower first request later replaces the results. Store a request generation, abort the previous fetch, and verify the generation before rendering. The server still treats both searches as independent safe requests.

  • Give the operation an owner
  • Abort superseded work
  • Ignore stale completions
  • Preserve accessible loading and result status

Worked example

Implement latest-search-wins behaviour

  1. Increment a generation counter and abort the previous controller.
  2. Render a loading state tied to the current generation.
  3. Fetch with the new signal and check response.ok.
  4. Before applying data, confirm the generation is still current.
  5. Handle cancellation silently and render other failures with a recoverable message.

Checklist

Use this before acting

  • Model request states explicitly
  • Assign ownership or generation to overlapping work
  • Abort superseded or unmounted requests
  • Check HTTP status and content type
  • Keep untrusted content out of unsafe HTML sinks
  • Retry only safe or idempotent operations
  • Test reverse ordering and cancellation
  • Provide accessible status messages

Common mistakes

Failure patterns to avoid

  • Assuming response order matches request order
  • Showing cancellation as an error
  • Treating every resolved fetch as success
  • Retrying non-idempotent requests
  • Using one controller for unrelated operations
  • Replacing focused content unexpectedly

Practical exercise

Race-test one interactive feature

Choose autocomplete, filters, tabs, or navigation data. Add explicit states, cancellation, latest-intent protection, status announcements, and tests that resolve requests in every meaningful order.

Deliverable: A race-safe component with automated ordering and accessibility tests.

Sources and further reading

Primary and official references

Topic-specific takeaway

Reliable browser concurrency comes from explicit ownership, cancellation, stale-result protection, and accessible request states.

Continue with the right depth

Find the book, lesson, topic, or pathway that matches the decision in front of you.

Search the lesson library, compare all eleven books, browse focused topic hubs, or choose a guided pathway. Teen academy progress remains on the visitor's device.

CallFree reviewFind a path