-
Notifications
You must be signed in to change notification settings - Fork 337
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
Add option to reject the fetch promise automatically after a certain time elapsed (with no API for arbitrary aborts) #179
Comments
This comment has been minimized.
This comment has been minimized.
2 similar comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
FYI this corresponds to the behaviour of XHR timeout. Which is what #20 is requesting. |
Something like this just better than just specifying integer for timeout parameter. Manually cancelling the request is a thing. var cancelpromise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000);
});
var cancelpromise2 = /* a promise that will be resolved when user clicks cancel */;
var lastpromise = Promise.race([cancelpromise1, cancelpromise2]);
fetch(..., { timeout: lastpromise })
... |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
It would help though if this was motivated a bit beyond "less wasteful". Is this primarily about ergonomics? Is it different from XMLHttpRequest's timeout? |
What I'm proposing is functionally the same as XHR's timeout. Ergonomics is a very important part of it, because for a robust web app the timeout has to be added to every single I know this from experience of developing a major PWA. We've found that there are unbelievably broken phones/mobile operators that made connections appear infinitely slow (similar to what @jakearchibald calls Lie-Fi) so our requests would get stuck waiting forever, and in turn keep related bits of logic or UI similarly stuck all over the place. I have fixed this by adding timeouts to our XHR calls, and contributed such interface to superagent. |
To be clear, I was not trying to dismiss the ergonomics perspective. Mostly making sure I understood the technical requirements. I think I'm supportive of adding this as a shorthand for calling https://fetch.spec.whatwg.org/#abort-fetch. I'd suggest we call it The main thing we lack is active implementer interest and folks to make all necessary changes (PR Fetch, PR WPT). |
That's great, but it should remain internal, i.e. it should trigger ontimeout not onabort. |
I use this, based on @buraktamturk's suggestion. const networkTimeoutError = new Error('Network request timeout')
function getTimeout({ timeout }) {
if (timeout && timeout.constructor === Promise) {
return timeout
}
if (typeof timeout === 'number') {
return new Promise(resolve => {
setTimeout(resolve, timeout)
})
}
}
export default function fetchWithTimeout(url, config) {
return new Promise((resolve, reject) => {
let completed = false
const timeout = getTimeout(config)
const wrap = (thing, ...pre) => (...args) => {
if (!completed) {
completed = true
return thing(...pre, ...args)
}
}
delete config.timeout
if (timeout) {
timeout.then(wrap(reject, networkTimeoutError))
}
return fetch(url, config)
.then(wrap(resolve))
.catch(wrap(reject))
})
} |
Does the caller need to be able to distinguish between cancelation and timing out? |
I had totally missed this issue, and wrote up some arguments in #951. I agree that the ergonomics are paramount (to cover the 90% case) because literally every
To eliminate the hanging failure case the This is similar to what Go does for their
Thanks! |
I'm still interested in an answer to the question I raised above as One high-level question I have for @kornelski is that although it was said this would be equivalent to XMLHttpRequest, the way OP reads to me is that we'd wait up to X seconds for the first chunk and after that the timeout no longer applies, whereas XMLHttpRequest timeout (and aborting) continues affecting subsequent chunks. |
Indeed, I've mixed up two concerns:
I think case 1 is solved. For case 2 I've written my XHR-based client that split timeout into timeout for the initial response (http headers) and timeout for the whole body. That ended up being close enough to solve the problem of distinguishing working slow connections from not getting any server response. Anyway, I'm not working any more on the project that motivated this feature request, so I don't have up to date information whether this is still needed. |
Well, you did also file #180 and maybe we'll get signals for individual read operations on a stream which would address that case on a per-chunk basis. And I guess timeout for response, but not response's body, can be implemented in userland as well because you can prevent calling |
Happened to find this but I think this can be closed now given we have AbortSignal and timeouts |
Actually just saw Anne's comment about clarification about which timeout this is:
|
My primary concern at this point is the ergonomics (readability and writeability) of this: fetch(url, { signal: AbortSignal.timeout(8000) }); Semantically convoluted on a skim, and just significantly longer than it needs to be for 99% of cases. We need to add this on basically every request. So I'm of the very strong opinion that this should not be closed until we have something ergonomically ~equivalent to: fetch(url, { timeout: 8000 }); And probably handled in a similar way to Go, as mentioned by ianstormtaylor in an earlier comment in this thread. |
I'd like an option to have a timeout/deadline for the server to respond, so that if the response doesn't arrive within a specified number of seconds, the fetch promise is rejected and internally (i.e. without any sort of abort/cancellation API exposed to JS) the request is aborted by the browser on the TCP/IP level, so that bandwidth is not wasted in case the response does come later.
It'd be less wasteful equivalent of:
I wouldn't mind if the timeout was automagically propagated to
response.json()
, so that promise would be rejected too after the deadline.Use-cases:
In such cases it seems that the browser is unaware that it has an unusable network connection, makes a request and never gives up waiting for a response (perhaps the request was successfully sent or at least was buffered somewhere along the way).
In such cases adding a deadline helps identify unusable network or servers quicker (the developer knows how fast the server is supposed to respond) and allows the application react to the situation rather than getting stuck forever (or for as long as very conservative deadlines are built into the browser or networking stack) or worse, having open and unusable connections exhaust browser's limit of open connections.
The text was updated successfully, but these errors were encountered: