Skip to content
javascript

How to timeout fetch requests in JavaScript

Feb 22, 2023Abhishek EH3 Min Read
How to timeout fetch requests in JavaScript

You might have observed long delays when fetching data from API sometimes. It might be happening due to various reasons like network issue on the client end, DNS lookup issues, servers taking too long to respond, etc.

In such scenarios, it is a good practice to cancel the request after a period of time and inform the user about the same using some error messages.

In my previous article, I explained how to cancel previous requests in fetch. We will be using a similar approach here.

Setting up the server

If you need to test the code, you would need an API endpoint. If you already have one, you can skip this section.

Install json-server globally:

1npm install -g json-server

In an empty folder, create a file named db.json with the following data:

1{"users":[{"id":1,"name":"Leanne Graham","username":"Bret","email":"[email protected]","address":{"street":"Kulas Light","suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","geo":{"lat":"-37.3159","lng":"81.1496"}},"phone":"1-770-736-8031 x56442","website":"hildegard.org","company":{"name":"Romaguera-Crona","catchPhrase":"Multi-layered client-server neural-net","bs":"harness real-time e-markets"}},{"id":2,"name":"Ervin Howell","username":"Antonette","email":"[email protected]","address":{"street":"Victor Plains","suite":"Suite 879","city":"Wisokyburgh","zipcode":"90566-7771","geo":{"lat":"-43.9509","lng":"-34.4618"}},"phone":"010-692-6593 x09125","website":"anastasia.net","company":{"name":"Deckow-Crist","catchPhrase":"Proactive didactic contingency","bs":"synergize scalable supply-chains"}},{"id":3,"name":"Clementine Bauch","username":"Samantha","email":"[email protected]","address":{"street":"Douglas Extension","suite":"Suite 847","city":"McKenziehaven","zipcode":"59590-4157","geo":{"lat":"-68.6102","lng":"-47.0653"}},"phone":"1-463-123-4447","website":"ramiro.info","company":{"name":"Romaguera-Jacobson","catchPhrase":"Face to face bifurcated interface","bs":"e-enable strategic applications"}},{"id":4,"name":"Patricia Lebsack","username":"Karianne","email":"[email protected]","address":{"street":"Hoeger Mall","suite":"Apt. 692","city":"South Elvis","zipcode":"53919-4257","geo":{"lat":"29.4572","lng":"-164.2990"}},"phone":"493-170-9623 x156","website":"kale.biz","company":{"name":"Robel-Corkery","catchPhrase":"Multi-tiered zero tolerance productivity","bs":"transition cutting-edge web services"}},{"id":5,"name":"Chelsey Dietrich","username":"Kamren","email":"[email protected]","address":{"street":"Skiles Walks","suite":"Suite 351","city":"Roscoeview","zipcode":"33263","geo":{"lat":"-31.8129","lng":"62.5342"}},"phone":"(254)954-1289","website":"demarco.info","company":{"name":"Keebler LLC","catchPhrase":"User-centric fault-tolerant solution","bs":"revolutionize end-to-end systems"}},{"id":6,"name":"Mrs. Dennis Schulist","username":"Leopoldo_Corkery","email":"[email protected]","address":{"street":"Norberto Crossing","suite":"Apt. 950","city":"South Christy","zipcode":"23505-1337","geo":{"lat":"-71.4197","lng":"71.7478"}},"phone":"1-477-935-8478 x6430","website":"ola.org","company":{"name":"Considine-Lockman","catchPhrase":"Synchronised bottom-line interface","bs":"e-enable innovative applications"}},{"id":7,"name":"Kurtis Weissnat","username":"Elwyn.Skiles","email":"[email protected]","address":{"street":"Rex Trail","suite":"Suite 280","city":"Howemouth","zipcode":"58804-1099","geo":{"lat":"24.8918","lng":"21.8984"}},"phone":"210.067.6132","website":"elvis.io","company":{"name":"Johns Group","catchPhrase":"Configurable multimedia task-force","bs":"generate enterprise e-tailers"}},{"id":8,"name":"Nicholas Runolfsdottir V","username":"Maxime_Nienow","email":"[email protected]","address":{"street":"Ellsworth Summit","suite":"Suite 729","city":"Aliyaview","zipcode":"45169","geo":{"lat":"-14.3990","lng":"-120.7677"}},"phone":"586.493.6943 x140","website":"jacynthe.com","company":{"name":"Abernathy Group","catchPhrase":"Implemented secondary concept","bs":"e-enable extensible e-tailers"}},{"id":9,"name":"Glenna Reichert","username":"Delphine","email":"[email protected]","address":{"street":"Dayna Park","suite":"Suite 449","city":"Bartholomebury","zipcode":"76495-3109","geo":{"lat":"24.6463","lng":"-168.8889"}},"phone":"(775)976-6794 x41206","website":"conrad.com","company":{"name":"Yost and Sons","catchPhrase":"Switchable contextually-based project","bs":"aggregate real-time technologies"}},{"id":10,"name":"Clementina DuBuque","username":"Moriah.Stanton","email":"[email protected]","address":{"street":"Kattie Turnpike","suite":"Suite 198","city":"Lebsackbury","zipcode":"31428-2261","geo":{"lat":"-38.2386","lng":"57.2232"}},"phone":"024-648-3804","website":"ambrose.net","company":{"name":"Hoeger LLC","catchPhrase":"Centralized empowering task-force","bs":"target end-to-end models"}}]}

Now open the terminal and run:

1json-server --watch db.json -d 10000

This will start a server and you should be able to access the list of users at http://localhost:3000/users The above URL will respond after 10 seconds since we have mentioned a 10s delay while starting json-server.

Creating data fetch function

We can use the fetch API to fetch the data from the server as shown below:

1const loadData = async url => {
2 const response = await fetch(url)
3 const data = await response.json()
4 console.log({ data })
5}
6loadData("http://localhost:3000/users")

If you run the above code in the browser console, or in your application, you should be able to see the data logged in the console after 10 seconds.

Adding timeout feature

Now let's add the timeout feature to the loadData function.

1const loadData = async (url, timeoutThreshold) => {
2 const controller = new AbortController()
3
4 const timeoutId = setTimeout(() => {
5 controller.abort()
6 }, timeoutThreshold)
7 const response = await fetch(url, {
8 signal: controller.signal,
9 })
10 clearTimeout(timeoutId)
11 const data = await response.json()
12 return data
13}

Here we are passing the timeout value as 5 seconds. After 5 seconds, we are calling the controller.abort() inside the setTimeout function. Also, we are passing the AbortController signal to the fetch call, so that it can be aborted.

We can call the above function inside a try-catch block and check if the exception is caused by AbortError, then handle the error accordingly.

1const getData = async () => {
2 try {
3 const data = await loadData("http://localhost:3000/users", 5000)
4 console.log({ data })
5 } catch (error) {
6 if (error.name === "AbortError") {
7 // handle error
8 }
9 }
10}
11getData()

Do follow me on twitter where I post developer insights more often!

© 2024 CodingDeft.Com