Post cover

How to Timeout a fetch() Request

Updated March 20, 2023

Normally, you should not rely on the network when we are working with it. The network is unreliable because an HTTP request or response can fail:

  • The user is offline
  • DNS lookup failed
  • The server doesn't respond
  • The server responds but with an error
  • and more.

Users are OK to wait up to 8 seconds for simple requests to complete. That's why you need to set a timeout on the network requests and inform the user after 8 seconds about the network problems.

I'll show you how to use setTimeout(), the abort controller, and fetch() to implement configurable request timeouts.

Before I go on, let me recommend something to you.

If you want to significantly improve your JavaScript knowledge, take the amazingly useful course "Modern JavaScript From The Beginning 2.0" by Brad Traversy. Use the coupon code "DMITRI" and get 20% discount!

1. Default fetch() timeout

By default a fetch() request timeouts at the time indicated by the browser. In Chrome a network request timeouts at 300 seconds, while in Firefox at 90 seconds.

javascript
async function loadGames() {
const response = await fetch('/games');
// fetch() timeouts at 300 seconds in Chrome
const games = await response.json();
return games;
}

300 seconds and even 90 seconds are way more than a user would expect a network request to complete.

As an experiment, in the demo the /games API response takes 301 seconds. Click Load games button to start the request, and it will timeout at 300 seconds (in Chrome).

2. Timeout a fetch() request

fetch() API by itself doesn't allow canceling programmatically a request. To stop a request at the desired time you also need an abort controller.

The following fetchWithTimeout() is an improved version of fetch() that creates requests with a configurable timeout:

javascript
async function fetchWithTimeout(resource, options = {}) {
const { timeout = 8000 } = options;
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
const response = await fetch(resource, {
...options,
signal: controller.signal
});
clearTimeout(id);
return response;
}

First, const { timeout = 8000 } = options extracts the timeout param in milliseconds from the options object (defaults to 8 seconds).

const controller = new AbortController() creates an instance of the abort controller. This controller allows you stop fetch() requests at will. A new abort controller must be created for each request, in other words, controllers aren't reusable.

const id = setTimeout(() => controller.abort(), timeout) starts a timing function. After timeout time, if the timing function wasn't cleared, controller.abort() cancels the fetch request.

Next line await fetch(resource, { ...option, signal: controller.signal }) starts properly the fetch request. Note the special controller.signal value assigned to signal property: it connectes fetch() with the abort controller.

Finally, clearTimeout(id) clears the abort timing function if the request completes earlier than timeout time passed.

Now here's how to use fetchWithTimeout():

javascript
async function loadGames() {
try {
const response = await fetchWithTimeout('/games', {
timeout: 6000
});
const games = await response.json();
return games;
} catch (error) {
// Timeouts if the request takes
// longer than 6 seconds
console.log(error.name === 'AbortError');
}
}

Try the demo.

fetchWithTimeout() (instead of simple fetch()) starts a request that will be canceled at timeout time — 6 seconds.

If the request to /games hasn't finished in 6 seconds, then the request is canceled and a timeout error is thrown.

You can use the expression error.name === 'AbortError' inside the catch block to determine if there was a request timeout.

Open the demo and click Load games button. The request to /games timeouts because it takes longer than 6 seconds.

3. Summary

By default a fetch() request timeouts at the time set up by the browser. In Chrome, for example, this setting is 300 seconds. That's way longer than a user would expect for a network request to complete.

A good approach to network requests is to configure a request timeout of about 8 - 10 seconds.

Using setTimeout() and abort controller you can create fetch() requests that are configured to timeout when you'd like to.

Check the browser support for the abort controller. There's also a polyfill for it.

Note that there's no way to stop a fetch() request without using an abort controller. Don't use solutions like this.

What good practices regarding network requests do you know? Please write a comment!

Like the post? Please share!

Quality posts into your inbox

I regularly publish posts containing:

  • Important JavaScript concepts explained in simple words
  • Overview of new JavaScript features
  • How to use TypeScript and typing
  • Software design and good coding practices

Subscribe to my newsletter to get them right into your inbox.

Join 7094 other subscribers.
Dmitri Pavlutin

About Dmitri Pavlutin

Tech writer and coach. My daily routine consists of (but not limited to) drinking coffee, coding, writing, coaching, overcoming boredom 😉.

Quality posts into your inbox

I regularly publish posts containing:

  • Important JavaScript concepts explained in simple words
  • Overview of new JavaScript features
  • How to use TypeScript and typing
  • Software design and good coding practices

Subscribe to my newsletter to get them right into your inbox.

Join 7094 other subscribers.
Dmitri Pavlutin

About Dmitri Pavlutin

Tech writer and coach. My daily routine consists of (but not limited to) drinking coffee, coding, writing, coaching, overcoming boredom 😉.