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

timers: fix clearInterval to work with timers from setTimeout #19952

Closed
wants to merge 1 commit into from

Conversation

remusao
Copy link
Contributor

@remusao remusao commented Apr 11, 2018

According to HTML Living Standard, "either method [clearInterval or
clearTimeout] can be used to clear timers created by setTimeout() or
setInterval()."[1].

The current implementation of clearTimeout is already able to destroy a
timer created by setInterval, but not the other way around.

Refs: https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval

Checklist
  • make -j4 jstest (UNIX)
  • tests are included
  • commit message follows commit guidelines
  • documentation is changed or added

Affected core subsystem(s)

timers.

@nodejs-github-bot nodejs-github-bot added the timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. label Apr 11, 2018
Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, just a few small comments.

// * Refs: https://nodejs.org/api/timers.html#timers_class_timeout

const assert = require('assert');
const Timer = require('timers');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't import timers in our timer tests. You can just use the global versions.


// Disarm timeout with setInterval.
const timeout = Timer.setTimeout(() => {
nbTimersTriggered += 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use common.mustNotCall instead for both of these.

Timer.clearInterval(timeout);

// Check that no callback was fired.
setTimeout(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once you convert to use common.mustNotCall you can just remove this whole block.

// Disarm timeout with setInterval.
const timeout = Timer.setTimeout(() => {
nbTimersTriggered += 1;
}, common.platformTimeout(20));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

common.platformTimeout isn't necessary. You can also just use 1 for the timeout value since it shouldn't execute regardless.

lib/timers.js Outdated
// It's allowed to use clearInterval to kill a setTimeout, which has its
// _repeat attribute to `null` already.
if (timer._repeat) {
timer._repeat = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all honesty, I would almost just go with exports.clearInterval = clearTimeout; The distinction is pretty meaningless especially since they're now interchangeable. Unsetting _repeat doesn't do anything. Or we could do:

exports.clearInterval = function clearInterval(timer) {
  clearTimeout(timer);
};

Mostly to appease stack traces, etc. with differing function names.

@remusao
Copy link
Contributor Author

remusao commented Apr 11, 2018

@apapirovski Thank you so much for your review. Is it alright if I amend my commit or should I create another one to implement your suggestions?

// clearTimeout and clearInterval can be used to clear timers created from
// both setTimeout and setInterval, as specified by HTML Living Standard:
// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
clearTimeout(timer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just set it to the same function instead of creating this wrapper?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I brought up this option for the sake of users who care about the function name for profilers, stack traces and the like. I personally would just go with exports.clearInterval = clearTimeout; but I'm not certain how other collaborators might feel about it.

Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small nits left. (And yep, amending commits is perfectly fine.)

// * Refs: https://nodejs.org/api/timers.html#timers_class_timeout

// Disarm interval with clearTimeout.
const interval = setInterval(common.mustNotCall(), common.platformTimeout(20));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: common.platformTimeout(20) can just become 1 now. We only use common.platformTimeout when the test is timing sensitive. Since in this test no timeouts will execute — unless it's broken — it doesn't need that extra overhead.

const interval = setInterval(common.mustNotCall(), common.platformTimeout(20));
clearTimeout(interval);

// Disarm timeout with setInterval.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/setInterval/clearInterval

Copy link
Member

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with @apapirovski comments addressed.

Copy link
Contributor

@Fishrock123 Fishrock123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please set timer._repeat = null; in clearTimeout? Thanks!

Also, here's a CI run: https://ci.nodejs.org/job/node-test-pull-request/14210/

// clearInterval and that timers created with setInterval can be disarmed by
// clearTimeout.
//
// This behavior is documented in Node.js' documentation and the HTML Living
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I don't see this behavior noted in the Node.js docs? This PR also doesn't contain doc updates.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be passed to clearTimeout() or clearInterval() (respectively) in order to cancel the scheduled actions.

Is not the same as "it can be passed to either". I'm impartial to documenting it, but mentions of the docs should be correct. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, I misunderstood the current documentation. Will update it. Thanks!

@apapirovski
Copy link
Member

apapirovski commented Apr 12, 2018

Could you please set timer._repeat = null; in clearTimeout? Thanks!

@Fishrock123 is there a specific reason we want this?

To elaborate: _repeat used to be a function reference (which then held a reference to the interval, so it could've potentially leaked memory) so any clearing that used to happen was to remove that reference. After we made _repeat just be null or the same value as _idleTimeout, I see no reason that clearing it is necessary.

@remusao
Copy link
Contributor Author

remusao commented Apr 12, 2018

Thank you for the reviews. I updated with the following changes:

  • Amend commit to be accurate regarding the state of the documentation.
  • Fix documentation to reflect the new behavior.
  • Simplify tests.

According to HTML Living Standard, "either method [clearInterval or
clearTimeout] can be used to clear timers created by setTimeout() or
setInterval()."[1].

The current implementation of clearTimeout is already able to destroy a
timer created by setInterval, but not the other way around.

Refs: https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
Copy link
Contributor

@Fishrock123 Fishrock123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok seems good to me. I was thinking it was still a function.

I suppose if it was set and the timer somehow got re-enrolled we'd want to keep it anyways (thinking of when we might support extending the timers prototype).

@remusao
Copy link
Contributor Author

remusao commented Apr 13, 2018

@Fishrock123 Thanks for your review. Let me know if there is anything I can do on this one.

@BridgeAR
Copy link
Member

@BridgeAR BridgeAR added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Apr 15, 2018
@apapirovski
Copy link
Member

FWIW I do think this could potentially be semver-major since it would make clearInterval clear timeouts which it didn't used to. Thoughts?

@BridgeAR
Copy link
Member

@apapirovski well in that case the user originally intended to clear the timeout and it was a bug in the users code that it was not cleared. So it seems like a bug fix to me. We can of course run a CITGM to see if anything pops up.

@apapirovski
Copy link
Member

well in that case the user originally intended to clear the timeout and it was a bug in the users code that it was not cleared.

Or they have some weird structure that stores both timeouts and intervals but only want to clear the intervals. And yes, I know it's far fetched but just pointing it out.

We should at least let this bake before back-porting to LTS.

BridgeAR pushed a commit to BridgeAR/node that referenced this pull request Apr 16, 2018
According to HTML Living Standard, "either method [clearInterval or
clearTimeout] can be used to clear timers created by setTimeout() or
setInterval().".

The current implementation of clearTimeout is already able to destroy a
timer created by setInterval, but not the other way around.

PR-URL: nodejs#19952
Refs: https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
Reviewed-By: Anatoli Papirovski <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Tiancheng "Timothy" Gu <[email protected]>
@BridgeAR
Copy link
Member

Landed in 978e152 🎉

@remusao congratulations on your first commit to Node.js and to officially becoming a contributor! 👍

@BridgeAR BridgeAR closed this Apr 16, 2018
@BridgeAR BridgeAR added the baking-for-lts PRs that need to wait before landing in a LTS release. label Apr 16, 2018
@remusao
Copy link
Contributor Author

remusao commented Apr 16, 2018

@BridgeAR Thank you very much! That was a very interesting experience and I will do it again if I can. I have to say that the documentation as to how to contribute was very detailed.

jasnell pushed a commit that referenced this pull request Apr 16, 2018
According to HTML Living Standard, "either method [clearInterval or
clearTimeout] can be used to clear timers created by setTimeout() or
setInterval().".

The current implementation of clearTimeout is already able to destroy a
timer created by setInterval, but not the other way around.

PR-URL: #19952
Refs: https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
Reviewed-By: Anatoli Papirovski <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Tiancheng "Timothy" Gu <[email protected]>
@MylesBorins
Copy link
Contributor

Is this something we want to backport to v8.x?

@targos targos removed the baking-for-lts PRs that need to wait before landing in a LTS release. label Sep 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants