Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch API request timeout?

I have a fetch-api POST request:

fetch(url, {
  method: 'POST',
  body: formData,
  credentials: 'include'
})

I want to know what is the default timeout for this? and how can we set it to a particular value like 3 seconds or indefinite seconds?

like image 420
Akshay Lokur Avatar asked Oct 15 '22 17:10

Akshay Lokur


People also ask

How do I set timeout on fetch API?

To set request timeout with Fetch API, we can use the AbortController constructor. const controller = new AbortController(); const timeoutId = setTimeout(() => controller. abort(), 5000); const req = async () => { const response = await fetch(url, { signal: controller.

Does fetch API timeout?

Unfortunately, it does not have the timeout option that other promise-based HTTP clients support.

How long does it take for Fetch to timeout?

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.

What is API request timeout?

Timeouts happen if a service takes more than 30 seconds to respond to a call. If a timeout occurs, you'll see the 500 error status code with details about the timeout in the response. Timeouts are typically caused by one of two things: The call involves too much data. There is a network/service issue.


3 Answers

Using a promise race solution will leave the request hanging and still consume bandwidth in the background and lower the max allowed concurrent request being made while it's still in process.

Instead use the AbortController to actually abort the request, Here is an example

const controller = new AbortController()

// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000)

fetch(url, { signal: controller.signal }).then(response => {
  // completed request before timeout fired

  // If you only wanted to timeout the request, not the response, add:
  // clearTimeout(timeoutId)
})

Alternative you can use the newly added AbortSignal.timeout(5000)... but it is not well implemented in most browser right now.


AbortController can be used for other things as well, not only fetch but for readable/writable streams as well. More newer functions (specially promise based ones) will use this more and more. NodeJS have also implemented AbortController into its streams/filesystem as well. I know web bluetooth are looking into it also. Now it can also be used with addEventListener option and have it stop listening when the signal ends

like image 124
Endless Avatar answered Oct 21 '22 12:10

Endless


Update since my original answer is a bit outdated I recommend using abort controller like implemented here: https://stackoverflow.com/a/57888548/1059828 or take a look at this really good post explaining abort controller with fetch: How do I cancel an HTTP fetch() request?

outdated original answer:

I really like the clean approach from this gist using Promise.race

fetchWithTimeout.js

export default function (url, options, timeout = 7000) {
    return Promise.race([
        fetch(url, options),
        new Promise((_, reject) =>
            setTimeout(() => reject(new Error('timeout')), timeout)
        )
    ]);
}

main.js

import fetch from './fetchWithTimeout'

// call as usual or with timeout as 3rd argument

fetch('http://google.com', options, 5000) // throw after max 5 seconds timeout error
.then((result) => {
    // handle result
})
.catch((e) => {
    // handle errors and timeout error
})
like image 28
Karl Adler Avatar answered Oct 21 '22 14:10

Karl Adler


Edit 1

As pointed out in comments, the code in the original answer keeps running the timer even after the promise is resolved/rejected.

The code below fixes that issue.

function timeout(ms, promise) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('TIMEOUT'))
    }, ms)

    promise
      .then(value => {
        clearTimeout(timer)
        resolve(value)
      })
      .catch(reason => {
        clearTimeout(timer)
        reject(reason)
      })
  })
}


Original answer

It doesn't have a specified default; the specification doesn't discuss timeouts at all.

You can implement your own timeout wrapper for promises in general:

// Rough implementation. Untested.
function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("timeout"))
    }, ms)
    promise.then(resolve, reject)
  })
}

timeout(1000, fetch('/hello')).then(function(response) {
  // process response
}).catch(function(error) {
  // might be a timeout error
})

As described in https://github.com/github/fetch/issues/175 Comment by https://github.com/mislav

like image 34
shakeel Avatar answered Oct 21 '22 14:10

shakeel