AbortController cancels a fetch, finally

A type-ahead search fires a request per keystroke, and the responses arrive out of order — so the results for “lap” can overwrite the results for “laptop”.

let controller;

async function search(term) {
  if (controller) controller.abort();
  controller = new AbortController();

  try {
    const res = await fetch(`/search?q=${term}`, { signal: controller.signal });
    render(await res.json());
  } catch (e) {
    if (e.name !== 'AbortError') throw e;
  }
}

Aborting rejects the promise with an AbortError, which has to be distinguished from a real failure or every cancellation is reported as a bug. The signal can be passed to several fetches to cancel them together, which is the neat part. It does not stop the server doing the work — the request has been sent — so this is about the client’s state rather than about saving anyone’s resources.