Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Really needs a timeout option #405

Closed
john-doherty opened this issue Oct 7, 2016 · 7 comments
Closed

Really needs a timeout option #405

john-doherty opened this issue Oct 7, 2016 · 7 comments

Comments

@john-doherty
Copy link

john-doherty commented Oct 7, 2016

This library needs the ability to provide a timeout interval as part of the options object:

fetch('/users', {
  method: 'POST',
  timeout: 1000,
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Hubot',
    login: 'hubot',
  })
})

which is then internally assigned to the xhr object xhr.timeout = 1000 (property details here).

I'm having to do this, which feels over-the-top:

function promiseTimeout(ms, promise){

  return new Promise(function(resolve, reject){

    // create a timeout to reject promise if not resolved
    var timer = setTimeout(function(){
        reject(new Error("promise timeout"));
    }, ms);

    promise
        .then(function(res){
            clearTimeout(timer);
            resolve(res);
        })
        .catch(function(err){
            clearTimeout(timer);
            reject(err);
        });
  });
};
promiseTimeout(1000, fetch('https://courseof.life/johndoherty.json'))
   .then(function(cvData){
      alert(cvData);
   })
   .catch(function(){
      alert('request either failed or timedout');
   });
@mislav
Copy link
Contributor

mislav commented Oct 7, 2016

Yes you're doing it right: #175 (comment)

We can't add a timeout option since it's not in the spec.

@DinoSourcesRex
Copy link

DinoSourcesRex commented Mar 15, 2017

Can you add it to the spec?

@jimmywarting
Copy link

const controller = new AbortController()
const signal = controller.signal
setTimeout(() => { 
  controller.abort()
}, 1000)

fetch(url, { signal })

@john-doherty
Copy link
Author

I built a fetch wrapper that adds offline functionality; it includes timeout/retry options:

var options = {

    // typical fetch property
    method: 'GET',

    // new offline property with optional config
    offline: {
        storage: 'localStorage',    // use localStorage (defaults to sessionStorage)
        timeout: 750,               // request timeout in milliseconds, defaults 730ms
        expires: 1000,              // expires in milliseconds, defaults 1000ms (set to -1 to check for updates with every request)
        debug: true,                // console log request info to help with debugging
        renew: false,               // if true, request is fetched regardless of expire state. Response is and added to cache

        // timeouts are not retried as they risk cause the browser to hang
        retries: 3,                 // number of times to retry the request before considering it failed, default 3 (timeouts are not retried)
        retryDelay: 1000,           // number of milliseconds to wait between each retry

        // used to generate per request cache keys (defaults to URL + METHOD hash if not provided)
        cacheKeyGenerator: function(url, opts, hash) {
            return 'myapp:' + url;
        }
    }
};

offlineFetch('http://www.orcascan.com/', options).then(function(data){
    // data contains response...
});

Source code here

@jimmywarting
Copy link

@john-doherty I would personal never use your fetch since service worker handles that much better... and is needed anyways to make the site to work offline

@john-doherty
Copy link
Author

john-doherty commented Apr 12, 2018

@jimmywarting I look forward to the day service workers are the answer. Unfortunately, they're not supported in the broad range of browsers/devices I needed to support. I therefore used AppCache to offline static resources and offlineFetch to offline API requests

@ianstormtaylor
Copy link

FWIW, I've opened an issue whatwg/fetch#951 with a proposal for a timeout option that solves 90% of use cases, in case anyone's interested. I think it's super important to add to make sure calls to fetch (or res.json()) don't hang indefinitely.

Also FWIW, the promise-based implementation above does not actually guarantee that the response body resolves within the timeout, so if you're using it in your codebase you likely still haven't protected yourself against infinitely hanging calls to res.json().

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 1, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants