Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How do I cancel an outdated fetch when a newer search begins?

Quick answer

Create an AbortController for each search and pass its signal to fetch. When a new search starts, abort the previous controller and create a new one. Treat an AbortError as an expected cancellation, not a search failure. Before displaying results, also check that the response still belongs to the current search; this prevents outdated results from replacing newer ones.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I send a fetch whenever someone types in a search box. If they type again before the first request finishes, how do I cancel the old one?

Geez

Keep track of the current request’s AbortController. At the start of each search, call abort() on the previous controller, create a new controller, and pass its signal in the fetch options. Fetch supports this signal-based cancellation; an aborted request rejects with an AbortError, which you can handle separately from other errors. [S1]

Here is a browser-side example. The route and display functions are placeholders: replace them with your own endpoint and UI code.

let activeController = null;

async function search(query) {
  activeController?.abort();

  const controller = new AbortController();
  activeController = controller;

  try {
    const response = await fetch(
      `/api/search?q=${encodeURIComponent(query)}`,
      { signal: controller.signal }
    );

    if (!response.ok) {
      throw new Error(`Search failed: ${response.status}`);
    }

    const results = await response.json();

    // Only the latest search may update the UI.
    if (activeController !== controller) return;
    renderResults(results);
  } catch (error) {
    if (error.name === "AbortError") return;
    if (activeController !== controller) return;
    showSearchError(error);
  }
}

The controller identity check is a second safeguard: even if an older operation reaches a later step, it cannot render after a newer search has taken ownership.

Follow-up question

Why check which controller is active if aborting already cancels the old request?

Geez

Cancellation and “only the newest result may render” are related but distinct protections. Aborting asks the in-progress fetch to stop. The identity check states the UI rule explicitly: only the request whose controller is still active can update results or show an error.

Keep that check immediately before every UI update. For example, if you later add another asynchronous step after parsing the response, check again after that step and before rendering. This makes the latest-search rule easy to preserve as the code changes.

Follow-up question

Should I show an error message when the previous search is aborted?

Geez

Usually, no: an abort caused by starting a newer search is expected control flow. In the example, the AbortError branch returns quietly, while other failures go to showSearchError(). That way, an intentional cancellation is not mistaken for another failure.

The fetch guide also notes a detail to keep in mind: if you abort after response headers arrive, reading the response body can still reject with AbortError. [S1] Keeping the abort check around the whole fetch-and-read operation handles that case too. The source establishes cancellation behavior; it does not prescribe what your interface should display.

Follow-up question

What should I verify when adapting this to my search box?

Geez

Try searches with deliberately different terms and confirm that only the latest term’s results are rendered. Also verify that a non-abort failure still reaches your error handler, while replacing a search does not show an error. If your code has extra asynchronous work between fetch and rendering, apply the current-controller check after that work as well.

Treat /api/search, renderResults, and showSearchError as placeholders, not built-in functions. This example covers request cancellation and stale-result protection; it does not define your endpoint, response format, or interface.

A practical checklist

  • Store the active AbortController where each search can access it.

  • Abort the previous controller before starting a replacement search.

  • Pass the new controller’s signal in the fetch options.

  • Return quietly for AbortError; handle other failures separately.

  • Check that the request is still current immediately before updating the UI.

A few more useful answers

What signal does fetch need for cancellation?

Pass the controller’s signal in the request options, as { signal: controller.signal }. Calling that controller’s abort() method cancels the associated operation. [S1]

Can reading the response body also be aborted?

Yes. The cited guide notes that body reading can reject with AbortError if the request is aborted after response headers arrive. Handle that as an expected cancellation too. [S1]

Does this example define how my search API responds?

No. The endpoint and UI functions are placeholders. Adapt the request and response handling to your own API and keep the current-request check before rendering.

Sources

References used for this guide.

  1. [S1] Using the Fetch API — Web APIs | MDN
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work