You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Remove Symbol.dispose integration in setTimeout and setInterval #58689
As part of the [Symbol.dispose] integration, the Timeout return type of setTimeout and setInterval support disposing (#48633). This was stabilized last week (#58467).
I think this integration should be removed, as the web platform setTimeout / setInterval do not support Symbol.dispose and never can, because it returns a number.
This means that folks may start writing new code that is incompatible between browser and Node, just because they use the Symbol.dispose integration here. That would be unfortunate.
It would also cause one more incompatibility between server side platforms with web setTimeout, and Node setTimeout (e.g Cloudflare Workers) (cc @jasnell).
@mcollina said in person that this was made stable recently enough to still remove it.
I don't understand. You can already write new code that is incompatible between browsers and node.js by using the returned Timeout object. I see plenty of new code use .unref() or .refresh().
I think the concern is more about creating more of a discrepancy and introducing an additional, more obscure error condition. If we take the "It's a node.js timeout so it doesn't matter" point of view then we likely are doing a disservice for cross-runtime interop/portability.
Reacted by Juan José, Matteo Collina, Luca Casonato and Kevin Gibbons
Would it be feasible on the very long term to have separate timers implementations? I.e. globalThis.setTimeout() that tries its best to follow the HTML spec, and node:timers.setTimeout()&node:timers/promises.setTimeout() that are not bound by interoperability constraints anymore.
I think we should just create new Node.js timer APIs that do all the things we want (return objects, disposable) and then we aren't tied to browser spec. We should support setTimeout and setImmediate as standardized, and then have separate APIs (call them delay or sleep or whatever else) and then it's the users choice if they need interop code to use the browser ones, and if not use the node ones.
Sadly, while I agree in concept, I suspect that deprecating our current setTimeout/setInterval return values would be quite difficult... On par with the deprecation of the Buffer constructor. I don't know if we'd be able to get there.
Any existing userland code that uses Node.js is using the node:timers implementation. How about this:
Deprecate accessing setTimeout/setInterval/ etc. as globals in favour of explicitly importing them from node:timers.
Keep the implementation independent from the HTML spec.
After EOL, reintroduce globalThis.setTimeout with behavior as close to the browser version as possible.
For users relying on Node.js's implementation, adding explicit import/require (which already should be a recommended practice) would be sufficient. They will retain full functionality with promises, disposers, refresh, etc.
For users using globalThis.setTimeout in browser-compatible way, nothing would change and they may get even more compatibility (such as implicit eval...).
IMHO this is much better than being stuck forever with an API that is both incompatible and unable to evolve.
I think we are steering away from the topic - if there are no plans of deprecating or changing the return type, then I don't really see the justification for removing Symbol.dispose from Timeout.
I don't think it should have been added and I wish timers returned a number, but if the reason for removing something is "this will benefit Deno/Cloudflare workers", I am not sure why we should support it. The same reason I supported passing async iterables to Response despite not being a fan of the change originally.
At this point, with my TSC hat firmly in place, largely because the disposal symbols have been in place for multiple major release cycles now, and because although official support in v8 for using only just landed, TypeScript and polyfills have been in general use now for a while, I believe a deprecation cycle is mandatory for removing these.
Secondly, I agree they can/should be removed in order to best facilitate interoperability across the ecosystem.
For the TSC members (13) who were in the meeting the consensus was that it would need to go through a deprecation cycle before being removed (which people agreed is unfortunate).
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
Activity
mcollina commentedon Jun 12, 2025
cc @nodejs/tsc @jasnell
jasnell commentedon Jun 12, 2025
Unfortunately, I think we'd likely need to take it through a deprecation cycle at this point but I'm fine with it.
KhafraDev commentedon Jun 12, 2025
I don't understand. You can already write new code that is incompatible between browsers and node.js by using the returned Timeout object. I see plenty of new code use .unref() or .refresh().
jasnell commentedon Jun 12, 2025
I think the concern is more about creating more of a discrepancy and introducing an additional, more obscure error condition. If we take the "It's a node.js timeout so it doesn't matter" point of view then we likely are doing a disservice for cross-runtime interop/portability.
LiviaMedeiros commentedon Jun 13, 2025
Would it be feasible on the
verylong term to have separate timers implementations? I.e.globalThis.setTimeout()that tries its best to follow the HTML spec, andnode:timers.setTimeout()&node:timers/promises.setTimeout()that are not bound by interoperability constraints anymore.Ethan-Arrowood commentedon Jun 13, 2025
I think we should just create new Node.js timer APIs that do all the things we want (return objects, disposable) and then we aren't tied to browser spec. We should support setTimeout and setImmediate as standardized, and then have separate APIs (call them delay or sleep or whatever else) and then it's the users choice if they need interop code to use the browser ones, and if not use the node ones.
jasnell commentedon Jun 13, 2025
Sadly, while I agree in concept, I suspect that deprecating our current setTimeout/setInterval return values would be quite difficult... On par with the deprecation of the Buffer constructor. I don't know if we'd be able to get there.
LiviaMedeiros commentedon Jun 13, 2025
Any existing userland code that uses Node.js is using the
node:timersimplementation. How about this:setTimeout/setInterval/ etc. as globals in favour of explicitly importing them fromnode:timers.globalThis.setTimeoutwith behavior as close to the browser version as possible.For users relying on Node.js's implementation, adding explicit
import/require(which already should be a recommended practice) would be sufficient. They will retain full functionality with promises, disposers, refresh, etc.For users using
globalThis.setTimeoutin browser-compatible way, nothing would change and they may get even more compatibility (such as implicit eval...).IMHO this is much better than being stuck forever with an API that is both incompatible and unable to evolve.
KhafraDev commentedon Jun 13, 2025
I think we are steering away from the topic - if there are no plans of deprecating or changing the return type, then I don't really see the justification for removing Symbol.dispose from Timeout.
I don't think it should have been added and I wish timers returned a number, but if the reason for removing something is "this will benefit Deno/Cloudflare workers", I am not sure why we should support it. The same reason I supported passing async iterables to Response despite not being a fan of the change originally.
jasnell commentedon Jun 22, 2025
At this point, with my TSC hat firmly in place, largely because the disposal symbols have been in place for multiple major release cycles now, and because although official support in v8 for
usingonly just landed, TypeScript and polyfills have been in general use now for a while, I believe a deprecation cycle is mandatory for removing these.Secondly, I agree they can/should be removed in order to best facilitate interoperability across the ecosystem.
mhdawson commentedon Jul 2, 2025
For the TSC members (13) who were in the meeting the consensus was that it would need to go through a deprecation cycle before being removed (which people agreed is unfortunate).
Removing from the TSC agenda.
github-actions commentedon Jul 20, 2026
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
timers: runtime-deprecate Timeout.prototype[Symbol.dispose]
github-actions commentedon Oct 19, 2026
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.