You don't need any polyfill anymore for abort a request in React Native 0.60 changelog

Here is a quick example from the doc of react-native:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
*/

'use strict';

const React = require('react');
const {Alert, Button, View} = require('react-native');

class XHRExampleAbortController extends React.Component<{}, {}> {
  _timeout: any;

  _submit(abortDelay) {
    clearTimeout(this._timeout);
    // eslint-disable-next-line no-undef
    const abortController = new AbortController();
    fetch('https://facebook.github.io/react-native/', {
      signal: abortController.signal,
    })
      .then(res => res.text())
      .then(res => Alert.alert(res))
      .catch(err => Alert.alert(err.message));
    this._timeout = setTimeout(() => {
          abortController.abort();
    }, abortDelay);
  }

  componentWillUnmount() {
    clearTimeout(this._timeout);
  }

  render() {
    return (
      <View>
        <Button
          title="Abort before response"
          onPress={() => {
            this._submit(0);
          }}
        />
        <Button
          title="Abort after response"
          onPress={() => {
            this._submit(5000);
          }}
        />
      </View>
    );
  }
}

module.exports = XHRExampleAbortController;
Answer from P-A Bouly on Stack Overflow
Top answer
1 of 4
15

You don't need any polyfill anymore for abort a request in React Native 0.60 changelog

Here is a quick example from the doc of react-native:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
*/

'use strict';

const React = require('react');
const {Alert, Button, View} = require('react-native');

class XHRExampleAbortController extends React.Component<{}, {}> {
  _timeout: any;

  _submit(abortDelay) {
    clearTimeout(this._timeout);
    // eslint-disable-next-line no-undef
    const abortController = new AbortController();
    fetch('https://facebook.github.io/react-native/', {
      signal: abortController.signal,
    })
      .then(res => res.text())
      .then(res => Alert.alert(res))
      .catch(err => Alert.alert(err.message));
    this._timeout = setTimeout(() => {
          abortController.abort();
    }, abortDelay);
  }

  componentWillUnmount() {
    clearTimeout(this._timeout);
  }

  render() {
    return (
      <View>
        <Button
          title="Abort before response"
          onPress={() => {
            this._submit(0);
          }}
        />
        <Button
          title="Abort after response"
          onPress={() => {
            this._submit(5000);
          }}
        />
      </View>
    );
  }
}

module.exports = XHRExampleAbortController;
2 of 4
8

I've written quite a bit actually about this subject. You can also find the first issue about the OLD lack of AbortController in React Native opened by me here

The support landed in RN 0.60.0 and you can find on my blog an article about this and another one that will give you a simple code to get you started on making abortable requests (and more) in React Native too. It also implements a little polyfill for non supporting envs (RN < 0.60 for example).

Discussions

AbortController is missing
Is this a bug report? Yes. AbortController is a new spec (you can find info here: https://developers.google.com/web/updates/2017/09/abortable-fetch) Have you read the Contributing Guidelines? Yes E... More on github.com
🌐 github.com
31
February 27, 2018
AbortSignal/AbortController doesn't work
Description AbortController / AbortSignal are used in javascript to cancel a request started with fetch, or any other async task that should be cancellable (docs here) In react native, there are se... More on github.com
🌐 github.com
12
March 13, 2025
React Native fetch abortController - figuring out abort reason
I'm in need of implementing following features for network/http client using fetch API. Timeout Also abort a previous request when user make multiple requests. I was able to implement both using ... More on stackoverflow.com
🌐 stackoverflow.com
Abort fetches in react native
and I'm trying to do so in react-native with your library ('cause the standard AbortController has yet to arrive) but it doesn't abort anything. More on github.com
🌐 github.com
10
February 27, 2018
🌐
React Native
reactnative.dev › docs › next › global-AbortController
AbortController · React Native
September 10, 2025 - This is unreleased documentation for React Native Next version. For up-to-date documentation, see the latest version (0.83). ... The global AbortController class, as defined in Web specifications.
🌐
DEV Community
dev.to › serifcolakel › canceling-requests-in-reactreact-native-a-comprehensive-guide-2ami
Canceling Requests in React/React Native: A Comprehensive Guide - DEV Community
April 6, 2025 - This article dives into various ways to handle cancellation of requests in React and React Native, covering: Axios: Using CancelToken to cancel requests. Fetch: Leveraging the AbortController API.
🌐
Giacomocerquone
giacomocerquone.com › blog › aborting-fetch-react-native
Aborting requests in React Native
While this could be a good approach to support old browsers when you’re doing a web app, this isn’t a viable option in React Native since only fetch is baked inside the core. Actually, I was wrong. As specified in this doc page XHR is backed into the React Native core and can be used to abort the connection.
🌐
GitHub
github.com › facebook › react-native › issues › 18115
AbortController is missing · Issue #18115 · facebook/react-native
February 27, 2018 - const controller = new AbortController(); const signal = controller.signal; setTimeout(() => controller.abort(), 5000); fetch(url, { signal }).then(response => { return response.text(); }).then(text => { console.log(text); }); My question is a technical one: is the react native core that needs to be updated in order to support this?
Author   giacomocerquone
🌐
GitHub
github.com › facebook › react-native › issues › 50015
AbortSignal/AbortController doesn't work · Issue #50015 · facebook/react-native
March 13, 2025 - Description AbortController / AbortSignal are used in javascript to cancel a request started with fetch, or any other async task that should be cancellable (docs here) In react native, there are se...
Author   lufinkey
Find elsewhere
🌐
GitHub
gist.github.com › kentcdodds › b36572b6e9227207e6c71fd80e63f3b4
abort-controller.js · GitHub
function useAbortController() { const abortControllerRef = React.useRef<AbortController>() const getAbortController = () => { return (abortControllerRef.current = abortControllerRef.current || new AbortController()) } React.useEffect(() => { return () => getAbortController().abort() }, []) const getSignal = React.useCallback(() => getAbortController().signal, []) return getSignal }
🌐
npm
npmjs.com › package › native-abort-controller
native-abort-controller - npm
$ npm install --save native-abort-controller abort-controller · import { AbortController } from 'native-abort-controller' const controller = new AbortController() const signal = controller.signal signal.addEventListener('abort', () => { console.log('aborted!') }) controller.abort()
      » npm install native-abort-controller
    
Published   Sep 20, 2021
Version   1.0.4
Author   Alex Potsides
🌐
Stack Overflow
stackoverflow.com › questions › 73167380 › react-native-fetch-abortcontroller-figuring-out-abort-reason
React Native fetch abortController - figuring out abort reason
Here is an example of what i did (in a react hook), but you should be able to apply the same logic and throw your own errors in whichever way you like · return new Promise((resolve, reject) => { if (abortControllerCancel.current.signal.aborted) { reject({ message: 'canceled', reason: 'canceled', }); } if (abortControllerDuplicate.current.signal.aborted) { reject({ message: 'canceled', reason: 'duplicate', }); } // the rest of the async function and resolving the promise abortControllerCancel.current.signal.addEventListener( 'abort', () => { reject({ message: 'canceled', reason: 'canceled', }); } ); abortControllerDuplicate.current.signal.addEventListener( 'abort', () => { reject({ message: 'canceled', reason: 'duplicate', }); } ); }
🌐
The New Stack
thenewstack.io › home › cancel asynchronous react app requests with abortcontroller
Cancel Asynchronous React App Requests with AbortController - The New Stack
April 24, 2024 - The following code creates a ref for the abortController and initializes it with an empty string. This prevents React from rerendering the component when the ref value changes. For each API request, it creates a new abortController and passes its signal property (a read-only property of the abortController that can be used to communicate with the request) to the request.
🌐
GitHub
github.com › mysticatea › abort-controller › issues › 3
Abort fetches in react native · Issue #3 · mysticatea/abort-controller
February 27, 2018 - Hi, I have a little problem... probably I'm misleading different specs. I read this article on how to abort a fetch request: https://developers.google.com/web/updates/2017/09/abortable-fetch and I'm trying to do so in react-native with y...
Author   giacomocerquone
🌐
npm
npmjs.com › package › abort-controller
abort-controller - npm
March 30, 2019 - Importing abort-controller/polyfill assigns the AbortController shim to the AbortController global variable if the native implementation was nothing.
      » npm install abort-controller
    
Published   Mar 30, 2019
Version   3.0.0
Author   Toru Nagashima
🌐
j-labs
j-labs.pl › home › tech blog › how to use the useeffect hook with the abortcontroller
AbortController in React. How to use the useEffect hook with the AbortControl? | j‑labs
December 9, 2025 - The AbortController interface provides a way to cancel ongoing asynchronous operations. When combined with React's useEffect hook, AbortController allows us to effectively manage asynchronous requests and prevent memory leaks.
🌐
Minimum
blog.minimum.se › 2017 › 07 › 24 › abort-fetch-abortcontroller-polyfill.html
AbortController polyfill for cancelling fetch() - molsson's blog
This new DOM API allows you to create an AbortController that in turn allows you to pass an AbortSignal into the fetch() call. Later on you can call .abort() on the controller to cancel the request. If you used the new API from a React application, it would look like this:
Top answer
1 of 3
22

Based off your code, there are a few corrections to make:

Don't return new Promise() inside an async function

You use new Promise if you're taking something event-based but naturally asynchronous, and wrap it into a Promise. Examples:

  • setTimeout
  • Web Worker messages
  • FileReader events

But in an async function, your return value will already be converted to a promise. Rejections will automatically be converted to exceptions you can catch with try/catch. Example:

async function MyAsyncFunction(): Promise<number> {
  try {
    const value1 = await functionThatReturnsPromise(); // unwraps promise 
    const value2 = await anotherPromiseReturner();     // unwraps promise
    if (problem)
      throw new Error('I throw, caller gets a promise that is eventually rejected')
    return value1 + value2; // I return a value, caller gets a promise that is eventually resolved
  } catch(e) {
    // rejected promise and other errors caught here
    console.error(e);
    throw e; // rethrow to caller
  }
}

The caller will get a promise right away, but it won't be resolved until the code hits the return statement or a throw.

What if you have work that needs to be wrapped with a Promise constructor, and you want to do it from an async function? Put the Promise constructor in a separate, non-async function. Then await the non-async function from the async function.

function wrapSomeApi() {
  return new Promise(...);
}

async function myAsyncFunction() {
  await wrapSomeApi();
}

When using new Promise(...), the promise must be returned before the work is done

Your code should roughly follow this pattern:

function MyAsyncWrapper() {
  return new Promise((resolve, reject) => {
    const workDoer = new WorkDoer();
    workDoer.on('done', result => resolve(result));
    workDoer.on('error', error => reject(error));
    // exits right away while work completes in background
  })
}

You almost never want to use Promise.resolve(value) or Promise.reject(error). Those are only for cases where you have an interface that needs a promise but you already have the value.

AbortController is for fetch only

The folks that run TC39 have been trying to figure out cancellation for a while, but right now there's no official cancellation API.

AbortController is accepted by fetch for cancelling HTTP requests, and that is useful. But it's not meant for cancelling regular old work.

Luckily, you can do it yourself. Everything with async/await is a co-routine, there's no pre-emptive multitasking where you can abort a thread or force a rejection. Instead, you can create a simple token object and pass it to your long running async function:

const token = { cancelled: false }; 
await doLongRunningTask(params, token); 

To do the cancellation, just change the value of cancelled.

someElement.on('click', () => token.cancelled = true); 

Long running work usually involves some kind of loop. Just check the token in the loop, and exit the loop if it's cancelled

async function doLongRunningTask(params: string, token: { cancelled: boolean }) {
  for (const task of workToDo()) {
    if (token.cancelled)
      throw new Error('task got cancelled');
    await task.doStep();
  }
}

Since you're using react, you need token to be the same reference between renders. So, you can use the useRef hook for this:

function useCancelToken() {
  const token = useRef({ cancelled: false });
  const cancel = () => token.current.cancelled = true;
  return [token.current, cancel];
}

const [token, cancel] = useCancelToken();

// ...

return <>
  <button onClick={ () => doLongRunningTask(token) }>Start work</button>
  <button onClick={ () => cancel() }>Cancel</button>
</>;

hash-wasm is only semi-async

You mentioned you were using hash-wasm. This library looks async, as all its APIs return promises. But in reality, it's only await-ing on the WASM loader. That gets cached after the first run, and after that all the calculations are synchronous.

Even if it is wrapped in an async function or in a function returning a Promise, code must yield the thread to act concurrently, which hash-wasm does not appear to do in its main computation loop.

So how can you let your code breath if you've got CPU intensive code like what hash-wasm uses? You can do your work in increments, and schedule those increments with setTimeout:

for (const step of stepsToDo) {
  if (token.cancelled)
    throw new Error('task got cancelled');

  // schedule the step to run ASAP, but let other events process first
  await new Promise(resolve => setTimeout(resolve, 0));

  const chunk = await loadChunk();
  updateHash(chunk);
}

(Note that I'm using a Promise constructor here, but awaiting immediately instead of returning it)

The technique above will run slower than just doing the task. But by yielding the thread, stuff like React updates can execute without an awkward hang.

If you really need performance, check out Web Workers, which let you do CPU-heavy work off-thread so it doesn't block the main thread. Libraries like workerize can help you convert async functions to run in a worker.


That's everything I have for now, I'm sorry for writing a novel

2 of 3
0

I can suggest my library (use-async-effect2) for managing the cancellation of asynchronous tasks/promises. Here is a simple demo with nested async function cancellation:

    import React, { useState } from "react";
    import { useAsyncCallback } from "use-async-effect2";
    import { CPromise } from "c-promise2";
    
    // just for testing
    const factorialAsync = CPromise.promisify(function* (n) {
      console.log(`factorialAsync::${n}`);
      yield CPromise.delay(500);
      return n != 1 ? n * (yield factorialAsync(n - 1)) : 1;
    });
    
    function TestComponent({ url, timeout }) {
      const [text, setText] = useState("");
    
      const myTask = useAsyncCallback(
        function* (n) {
          for (let i = 0; i <= 5; i++) {
            setText(`Working...${i}`);
            yield CPromise.delay(500);
          }
          setText(`Calculating Factorial of ${n}`);
          const factorial = yield factorialAsync(n);
          setText(`Done! Factorial=${factorial}`);
        },
        { cancelPrevious: true }
      );
    
      return (
        <div>
          <div>{text}</div>
          <button onClick={() => myTask(15)}>
            Run task
          </button>
          <button onClick={myTask.cancel}>
            Cancel task
          </button>
        </div>
      );
    }
🌐
Wanago
wanago.io › home › using abortcontroller to deal with race conditions in react
Using AbortController to deal with race conditions in React
April 11, 2022 - With it, we can abort one or more fetch requests. To do this, we need to create an instance of the AbortController and use it when making the fetch request.
🌐
Medium
medium.com › @leonardobrunolima › how-to-cancel-abort-a-fetch-request-using-abortcontroller-b5ad39c10901
How to cancel/abort a fetch request using abortController | by Leonardo Bruno Lima | Medium
October 21, 2019 - In the method above, we simply created an abortController and grabbed the signal object and passed it to the request. Finally, we used a setTimeout to abort the request. We can try to call this method passing a low timeout value like 50 and increase to 200 and check the result.
🌐
Medium
medium.com › @icjoseph › using-react-to-understand-abort-controllers-eb10654485df
Using React to understand Abort Controllers | by Joseph Chamochumbi | Medium
November 18, 2022 - In case you didn’t know, browsers support an API called AbortController, which is typically used to cancel ongoing fetch requests. More info always available at MDN. ... An example using React’s useEffect.