Summary: in this tutorial, you’ll explore how to use the JavaScript AbortController
to cancel an ongoing network request.
Introduction to the JavaScript AbortController
AbortController
is a web API that allows you to abort network requests. It works by linking an AbortSignal
with network requests. This signal can be used to communicate with network requests to abort them when necessary.
Here are the steps for using an AbortController
to abort a fetch request:
First, create a AbortController
object using the new
keyword:
const controller = new AbortController();
Code language: JavaScript (javascript)
Second, get the signal
property of the AbortController
object. The signal
property is an instance of the AbortSignal
object:
const signal = controller.signal;
Code language: JavaScript (javascript)
This signal
can be passed to the fetch request, allowing us to control its behavior.
Third, pass a AbortSignal
object to the fetch method:
fetch(url, { signal });
Code language: JavaScript (javascript)
Alternatively, you can pass the signal
to the Request
object and use it in the fetch
method:
const request = new Request(url, { signal });
fetch(request);
Code language: JavaScript (javascript)
Fourth, abort the fetch request if necessary by calling the abort()
method of the AbortController
object.
controller.abort();
Code language: JavaScript (javascript)
For example, you make a fetch timeout after 2 seconds:
setTimeout(() => controller.abort(), 2000);
Code language: JavaScript (javascript)
It’s fine if you call abort() after the fetch has already been completed, fetch will ignore it.
Fifth, when you call the abort() method, it notifies the abort signal. You can listen to the abort event using the addEventListener on the signal object:
signal.addEventListener('abort', () => {
console.log(signal.aborted); // true
});
Code language: JavaScript (javascript)
Finally, you can react to an aborted fetch:
fetch(url, { signal }).then(response => {
return response.json();
}).then(data => {
console.log(data);
}).catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
}
});
Code language: JavaScript (javascript)
Note that the AbortError
is not a real error therefore we use an if
statement to handle the AbortError
specifically.
JavaScript AbortController example
In practice, you use the AbortController
when dealing with user interactions. For example, on a search page, you can abort a previous request when the user searches for a new search term.
We’ll build an app that searches for a term on Wikipedia and cancels the previous search request if the user starts a new one before the last one finishes.
Step 1. Create a new directory for storing the project files.:
mkdir wikipedia-search-abortable
Code language: JavaScript (javascript)
Step 2. Create the following directories and files within the project directory:
wikipedia-search-abortable
├── css
| └── style.css
├── img
| ├── spinner.svg
| └── wikipedia-logo.png
├── index.html
└── js
└── app.js
Code language: JavaScript (javascript)
Step 3. Create HTML structure in the index.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wikipedia Search</title>
<script src="./js/app.js" defer></script>
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<header>
<img src="./img/wikipedia-logo.png" alt="wikipedia">
<h1>Wikipedia Search</h1>
<form id="search">
<input type="search" name="term" id="term" placeholder="Enter a search term...">
</form>
</header>
<main>
<div id="searchResult"></div>
<div id="loading"></div>
<div id="error"></div>
</main>
</body>
</html>
Code language: HTML, XML (xml)
Step 4. Modify the app.js
file with the following code:
const form = document.querySelector('#search');
const termInput = document.querySelector('#term');
const error = document.querySelector('#error');
const loading = document.querySelector('#loading');
const resultsContainer = document.querySelector('#searchResult');
let controller = new AbortController();
const search = async (term) => {
// Abort the previous request
console.log('Abort the previous request');
controller.abort();
// Create a new controller for the new request
controller = new AbortController();
const signal = controller.signal;
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${term}`;
const response = await fetch(url, { signal });
const data = await response.json();
return data.query.search;
};
const resetSearchResult = () => {
error.innerHTML = '';
loading.innerHTML = '';
resultsContainer.innerHTML = '';
};
const handleSubmit = async (e) => {
e.preventDefault();
// reset search result
resetSearchResult();
// check if term is empty
const term = termInput.value;
if (term === '') return;
try {
// show the loading
loading.innerHTML = `<img src='./img/spinner.svg' alt='loading...'>`;
// make the search
const results = await search(term);
// show the search result
resultsContainer.innerHTML = renderSearchResult(results);
} catch (err) {
// show the error
error.innerHTML = `Something went wrong.`;
console.error(err);
} finally {
// hide the loading
loading.innerHTML = '';
}
};
const renderSearchResult = (results) => {
return results
.map(({ title, snippet, pageid }) => {
return `<article>
<a href="https://en.wikipedia.org/?curid=${pageid}">
<h2>${title}</h2>
</a>
<div class="summary">${snippet}...</div>
</article>`;
})
.join('');
};
form.addEventListener('submit', handleSubmit);
Code language: JavaScript (javascript)
How it works.
First, select the DOM elements using the querySelector
method:
const form = document.querySelector('#search');
const termInput = document.querySelector('#term');
const error = document.querySelector('#error');
const loading = document.querySelector('#loading');
const resultsContainer = document.querySelector('#searchResult');
Code language: JavaScript (javascript)
Second, create an AbortController
for aborting a fetch request:
let controller = new AbortController();
Code language: JavaScript (javascript)
Third, define a search function that calls the Wikipedia API based on an input search term:
const search = async (term) => {
// Abort the previous request
console.log('Abort the previous request');
controller.abort();
// Create a new controller for the new request
controller = new AbortController();
const signal = controller.signal;
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${term}`;
const response = await fetch(url, { signal });
const data = await response.json();
return data.query.search;
};
Code language: JavaScript (javascript)
In the search()
function, we call the abort()
method of the AbortController
object to cancel the previous search request if the user starts a new one:
controller.abort();
Code language: JavaScript (javascript)
Before making a new request, we create a new AbortController
object and pass its AbortSignal
to the fetch()
method:
controller = new AbortController();
const signal = controller.signal;
const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srsearch=${term}`;
const response = await fetch(url, { signal });
Code language: JavaScript (javascript)
Step 5. Define a function to reset the error, loading, and search result:
const resetSearchResult = () => {
error.innerHTML = '';
loading.innerHTML = '';
resultsContainer.innerHTML = '';
};
Code language: JavaScript (javascript)
Step 6. Define a handleSubmit()
function that executes the search when the form is submitted:
const handleSubmit = async (e) => {
e.preventDefault();
// reset search result
resetSearchResult();
// check if term is empty
const term = termInput.value;
if (term === '') return;
try {
// show the loading
loading.innerHTML = `<img src='./img/spinner.svg' alt='loading...'>`;
// make the search
const results = await search(term);
// show the search result
resultsContainer.innerHTML = renderSearchResult(results);
} catch (err) {
// show the error
error.innerHTML = `Something went wrong.`;
console.error(err);
} finally {
// hide the loading
loading.innerHTML = '';
}
};
Code language: JavaScript (javascript)
How it works.
First, prevent the form to submit to the server:
e.preventDefault();
Code language: JavaScript (javascript)
Second, call the resetSearchResult
function to reset the search result:
resetSearchResult();
Code language: JavaScript (javascript)
Third, return immediately if the search term is blank:
const term = termInput.value;
if (term === '') return;
Code language: JavaScript (javascript)
Fourth, show the loading progress indicator before making a search request:
loading.innerHTML = `<img src='./img/spinner.svg' alt='loading...'>`;
Code language: JavaScript (javascript)
Fifth, make a search request:
const results = await search(term);
Code language: JavaScript (javascript)
Sixth, display the search result:
resultsContainer.innerHTML = renderSearchResult(results);
Code language: JavaScript (javascript)
Seventh, display a user-friendly user message and log the error detail in the console:
} catch (err) {
// show the error
error.innerHTML = `Something went wrong.`;
console.error(err);
}
Code language: JavaScript (javascript)
Eighth, hide the loading indicator regardless of whether an error occurs or not:
} finally {
// hide the loading
loading.innerHTML = '';
}
Code language: JavaScript (javascript)
Ninth, define a function renderSearchResult
that renders the search result:
const renderSearchResult = (results) => {
return results
.map(({ title, snippet, pageid }) => {
return `<article>
<a href="https://en.wikipedia.org/?curid=${pageid}">
<h2>${title}</h2>
</a>
<div class="summary">${snippet}...</div>
</article>`;
})
.join('');
};
Code language: JavaScript (javascript)
Finally, register the handleSubmit
function as a submit event handler of the form:
form.addEventListener('submit', handleSubmit);
Code language: JavaScript (javascript)
Download the project source code
Download the project source code
Summary
- Use
AbortController
to abort a web request to prevent unnecessary network requests and handle user interactions efficiently.