Closed Bug 1753309 Opened 2 years ago Closed 2 years ago

Implement AbortSignal.timeout()

Categories

(Core :: DOM: Core & HTML, enhancement)

enhancement

Tracking

()

RESOLVED FIXED
100 Branch
Tracking Status
firefox100 --- fixed

People

(Reporter: d, Assigned: saschanaz)

References

(Blocks 1 open bug)

Details

(Keywords: dev-doc-complete)

Attachments

(3 files)

Depends on: 1752921
Blocks: dom

The implementation passes both https://wpt.live/dom/abort/AbortSignal.any.html and https://wpt.live/dom/abort/abort-signal-timeout.html. I am going to less active the next few weeks, so if this is urgent feel free to steal.

Bug 1734997 will probably use the timeout code too without any clamping.

Oh, I forgot to check this out. AFAICT the clamping can check TimeoutReason to not clamp for any new reasons.

sefeng is adding a flag to prevent clamping (for other reasons than this). Hopefully it can be reused.

Depends on: 1734997
Assignee: nobody → krosylight
Status: NEW → ASSIGNED
Attachment #9262446 - Attachment description: WIP: Bug 1753309 - Implement AbortSignal.timeout() → Bug 1753309 - Implement AbortSignal.timeout() r=smaug
Pushed by krosylight@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/53d1dd2040d5
Implement AbortSignal.timeout() r=smaug
Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 100 Branch

FF100 docs work for this can be tracked in https://github.com/mdn/content/issues/14641

Looking at the explainer the "more full example" shows handling for both a timeout abort and an abort signal triggered explicitly. Further down the document it seems to indicate that this is not actually possible - you can either timeout the signal or abort it but not both. Is that correct?

Does that mean that if you want to do both you still need to do the suggestion in https://github.com/whatwg/fetch/issues/951 ? :

const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 5000)
const res = await fetch('https://example.com', { signal: controller.signal })
const body = await res.json()
clearTimeout(timeoutId)

If not, what is the recommended way to handle this case?

Flags: needinfo?(d)

shows handling for both a timeout abort and an abort signal triggered explicitly.

That is not what the example shows. As it says in the comments, the "AbortError" case is for cases like the user pressing the stop button, or the page navigating away, or...

Flags: needinfo?(d)

shows handling for both a timeout abort and an abort signal triggered explicitly.

That is not what the example shows. As it says in the comments, the "AbortError" case is for cases like the user pressing the stop button, or the page navigating away, or...

**I understand that the example "shows" how you might catch the "AbortError" but I don't see how that can be triggered since you don't have the controller. Specifically, AbortSignal.timeout() returns an AbortSignal and there is no way to get hold of the AbortController so you can call abort on that signal (from the stop button).

Further down your comment appear support this case "requires future work", because otherwise why would you need fetch to take multiple signals?

To spell it out in excruciating detail, this is your example, which looks like it can catch a TimeoutError, AbortError or something else. The fetch only takes the signal returned by AbortSignal.timeout(). How would the code get a handle to the controller in order call abort on this?

try {
  const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
  const result = await res.text();
  // ...
} catch (e) {
  if (e.name === "TimeoutError") {
    // It took more than 10 seconds to get the result!
  } else if (e.name === "AbortError") {
    // The fetch was explicitly aborted, e.g. by the user pressing the stop button!
  } else {
    // Something horrible went wrong, like a network error!
  }
}

And then you say.

Future work: this feature would benefit greatly from a solution for combining AbortSignals, so that people could have an operation that aborts on either a timeout or an explicit abort. For example, something like this:

// NOT REAL CODE, YET:
const controller = new AbortController();
fetch(url, { signal: AbortSignal.all([AbortSignal.timeout(10_000), controller.signal]) });

abortButton.onclick = () => controller.abort();

I hope this has explained my confusion enough that you can explain where I'm completely missing the point?

Flags: needinfo?(d)

I understand that the example "shows" how you might catch the "AbortError" but I don't see how that can be triggered since you don't have the controller.

It can be triggered by the user pressing the stop button on their browser, which will cancel the fetch. The controller is not involved.

Flags: needinfo?(d)

Thanks very much, it did not occur to me that browser chrome might also stop a download. I've updated the docs to reflect this.

Regressions: 1771009
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: