Skip to content

Support Temporal.Duration as an argument to timeout-related APIs #1458

@lgarron

Description

@lgarron

What problem are you trying to solve?

Across various shells and programming languages, there are various methods to specify a duration for a timeout, and both seconds (e.g. sleep in most shells) and milliseconds (e.g. setTimeout(…) and AbortSignal.timeout(…) in the DOM API are common to encounter. If someone is not highly familiar with JS, the following may plausibly look like they do the same:

# shell
sleep 1
curl --connect-timeout 60 https://example.com
// JavaScript
setTimeout(() => {
  const request = fetch("https://example.com", {signal: AbortSignal.timeout(60)});
  // …
}, 1);

However, the latter uses timeouts that differ by a factor of 1,000. This kind of code also generally tends to be subject to more race conditions, making it plausible that that this kind of mistake is discovered well after it is initially coded.

This is not necessarily a huge stumbling block, but I think most programmers have experienced friction like this when switching between ecosystems and programming languages with contradicting conventions.

Some languages/standard libraries (e.g. thread::sleep(…) in Rust) require a timeout argument to be specified as a value that is much more common to construct in an unmistakable way (e.g. time::Duration::from_millis(10) in the example in the Rust docs linked above).

JavaScript must keep backwards compatibility for timeouts that accept milliseconds, but it can improve the situation by accepting Temporal.Duration values as arguments.

What solutions exist today?

Being careful? Using a value like 1_000 or const TIMEOUT_MILLISECONDS = 1_000 can improve readability, but:

  1. You already have to be aware of this in order to remember to do it.
  2. There are numbers like 15 that do not "obviously" represent just one of milliseconds (could mean just under one frame at 60fps) or seconds (could mean ¼ minute) at first glance.

How would you solve it?

Allow the following methods to accept a Temporal.Duration in addition to accepting a numeric value in milliseconds:

  • setTimeout(…, timeout, …)
  • setInterval(…, timeout, …)
  • AbortSignal.timeout(timeout)

This allows writing the following code, with a much more unmistakeable meaning:

AbortSignal.timeout(Temporal.Duration.from({ seconds: 1 }))

Linters could further enforce the use of Temporal.Duration as an argument in codebases that would like to prioritize this convention.

There are also additional opportunities to update APIs related to animation, but I think the ones above are most high-value and a great starting point for using Temporal in the DOM API.

Anything else?

I can see two "obvious" ways of acception Temporal.Duration as a timeout value in these cases.

  • Accept only instances of the built-in Temporal.Duration.
  • Accept any object that has a .total(…) method, and specify that the value of .total("milliseconds") is used to convert the parameter into a value to be interpreted as milliseconds.

I think the former would prevent polyfills and ponyfills from working without shenanigans (e.g. hooking up conditional prototype chains), so it would would certainly make it annoying (at least in the short term).

The latter seems relatively natural to me. It also might benefit from specifying a concept that can be reused in the future. Similar to ecosystems conventions (e.g. TypeScript types) like "Promise-like", this might be "Duration-like" or "total duration provider".

Metadata

Metadata

Assignees

No one assigned

    Labels

    addition/proposalNew features or enhancementsneeds implementer interestMoving the issue forward requires implementers to express interest

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions