How to use AbortController

How to use AbortController

Tags
Web Dev
Published
January 3, 2023
Author
Toan Ho

Prerequisites

To clearly understand my article, I think you can take a look at the articles below:
After reading these articles, you may find their examples to be too simple and not applicable to real life. This is why I am writing this article. If you have any questions, please leave a comment.

What is AbortController?

The AbortController interface represents a controller object that allows you to abort one or more Web requests as and when desired.
You can create a new AbortController object using the AbortController() constructor. Communicating with a DOM request is done using an AbortSignal object.

Why do we need to use AbortController?

For instance, when users want to search for something on our web application.
The request will be as follows:
  • Request 1 (R1): /search?q=kon
  • Request 2 (R2): /search?q=konvoy
  • Request 3 (R3): /search?q=konvoy+kegs
notion image
In the normal network, we expect responses to be returned in order. That means the R1 will complete first. Then comes R2 and R3.
But what if there's a problem with the server? Should R3 be completed first, then R2, and finally R1?
Take a look at the code below:
const [data, setData] = useState([]); setTimeout(async () => { try { if (keyword) { setLoading(true); const response = await searchSomething( { keyword: keyword, }, id ); setData(items); setLoading(false); } } catch (err) { console.error(err) } }, 300)
If R3 completes first, followed by R2 and then R1, the data will contain the result of R1, not R3. We certainly want to avoid this situation.
That's why we will use AbortController.

How to use AbortController?

Read the sample code below
class ApiOption { ... abort?: { key?: string; enabled?: boolean; }; } class ApiClient { // this is the key point I want to mention -> by saving the key + value // of abort controller, we easily trace them and cancel them private requests: Record<string, AbortController>; private async request( method: HttpMethods, endpoint: string, options?: ApiOption ) { // sample request key should be: GET/locations/search[order-form-w] const requestKey = `${method}${path}[${key || ''}]`; // we also provide an option to check if abort flag is enabled or not if (enabled) { // because we've already store the abortController instance // -> we can get and cancel it const previousRequest = this.requests[requestKey]; if (previousRequest) { // call this function to abort the previous request previousRequest.abort(); } } // init new AbortController const abortController = new AbortController(); // we will get the signal from AbortController instance const { signal } = abortController; // we'll save the abortController instance this.requests[requestKey] = abortController; await fetch(endpoint, { signal: signal, ... }); ... } public async searchSomething() { return this.request('GET', '/xxx/...', { abort: { enabled: true } }); } }
 

Use Case

In most cases, we need to combine debounce input and AbortController together.
Follow the example below. You’ll see:
  • When the user typing kon → because we already applied to debounce input → only kon is sent to our server.
  • The user continues typing → the 2nd request with konvoy keyword has been called → because we already applied AbortController ⇒ the 1st request has been canceled
Using this method, we do not need to be concerned about the data. Only the latest data will be returned.

Reference

Loading Comments...