DEV Community

Pavel Oreshkin
Pavel Oreshkin

Posted on

AbortController in web and how it can improve your app

Hi guys! Today I am going to tell you what is AbortController, why you possible need it and how it can improve the performance of your application.

Introduction

In a small IT chat, I conducted a survey and it turned out that only 9% of web developers used it in a real project, and 64% of web developers do not know what it is at all.

So let's get started!

The AbortController interface represents a controller object that allows you to abort one or more Web requests as and when desired.

This is a very simple interface that consists of the signal property and the abort method

const controller = new AbortController();
const signal = controller.signal;
const abort = controller.abort;
Enter fullscreen mode Exit fullscreen mode

We pass signal to the call method: fetch(url, { signal })
and with abort() this call can be stopped

Examples

Fetch

This simple code our application:

export default function App() {
  const [url, setUrl] = useState("users");
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    fetch(`https://jsonplaceholder.typicode.com/${url}`)
      .then((res) => res.json())
      .then((res) => {
        setData(res);
        setLoading(false);
      });
  }, [url]);

  return (
    <div className="App">
      <div className="nav">
        <Link to="/users" onClick={() => setUrl("users")}>
          users
        </Link>
        <Link to="/todos" onClick={() => setUrl("todos")}>
          todos
        </Link>
        <Link to="/posts" onClick={() => setUrl("posts")}>
          posts
        </Link>
      </div>
      <div className="page">
        <Switch>
          <Route path="/users" component={() => <div>Users page</div>} />
          <Route path="/todos" component={() => <div>Todos page</div>} />
          <Route path="/posts" component={() => <div>Posts page</div>} />
        </Switch>

        {loading ? (
          "loading..."
        ) : (
          <ul>
            {data?.splice(0, 5).map((item) => (
              <li key={item.id}>{item?.name || item?.title}</li>
            ))}
          </ul>
        )}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

and it works like this:

app without AbortController

As you can see all 3 requests reach the target and are displayed on the screen in turn

We can imagine a situation where the user navigates through our menu faster than the requests have time to be processed on the server, that mean we do unnecessary requests

For example: the user come to the "/user" page, a request has begun, next user come to the "/post" page, at this moment we assume that he no longer needs the "/user" page, and this request can be canceled and not load the server

This is how the code looks like with AbortController, I changed only useEffect:

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    setLoading(true);    
    fetch(`https://jsonplaceholder.typicode.com/${url}`, { signal })
      .then((res) => res.json())
      .then((res) => {
        setData(res);
        setLoading(false);
      });

    return () => {
      controller.abort();
    };
  }, [url]);
Enter fullscreen mode Exit fullscreen mode

and that's what happened:

app with AbortController

Unnecessary requests have been cancelled!

canceled request

This is the main point of performance!

Axios

identical with fetch

const controller = new AbortController();
axios.get('/user', { signal: controller.signal })
Enter fullscreen mode Exit fullscreen mode

GQL

GQL have almost the same way, but you need to use useRef

In the following example we cancel the request when we leave the page:

const controllerRef = useRef(new AbortController());

const [getUser, { data }] = useLazyQuery(USER_QUERY, {
  context: {
    fetchOptions: {
      signal: controllerRef.current.signal,
    },
  },
});

useEffect(() => {
  return () => controllerRef.current.abort();
}, []);
Enter fullscreen mode Exit fullscreen mode

Conclusion

AbortController is a simple and effective way to improve performance which you can try in your projects, good luck!

Top comments (0)