-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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: allow timers to be used as primitives #21152
Conversation
For web compatibility this allows timers to be stored as the key of an Object property and be passed back to corresponding method to clear the timer. Co-authored-by: Bradley Farias <bradley.meck@gmail.com>
+1, don't worry about attribution here. |
The double digit performance regressions still worry me. |
@mscdex Let me see what's going on. This doesn't match what I'm seeing locally... I'm also noticing a wide spread in the results. Let's run it again, not convinced the timers benchmarks are precise enough on the linux machine for some reason. Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/206/ |
if (timerInstance !== undefined) { | ||
timerInstance._onTimeout = null; | ||
unenroll(timerInstance); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👆 In the browser implementations I think there is some coercion going on as:
var i = setTimeout(()=>console.log("hi"), 1000);
clearTimeout({ [Symbol.toPrimitive]() { return i } })
// will clear the time
Would it make sense to instead of type checking just coerce the value to a number
(or whatever the correct steps may be).
@@ -123,6 +123,14 @@ Calling `timeout.unref()` creates an internal timer that will wake the Node.js | |||
event loop. Creating too many of these can adversely impact performance | |||
of the Node.js application. | |||
|
|||
### timeout[Symbol.toPrimitive]() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is rendered as an empty link in the GitHub and in HTML:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An example of how to fix such cases:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+ Should this section be placed before the timeout.unref()
heading ABC-wise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it depends on what convention we follow for symbols. I prefer it after but it could also be the first thing in the list. I wouldn't put it between ref & unref.
Will fix the link issue 👍
|
||
When coercing a `Timeout` to a primitive, a primitive will be generated that | ||
can be used to clear the `Timeout`. This allows enhanced compatibility with | ||
browser `setTimeout`, and `setInterval` implementations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`setTimeout`
-> `setTimeout()`
?
`setInterval`
-> `setInterval()`
?
Benchmark results still seem to be about the same (double digit regressions), despite the increased number of runs. |
Yeah, I'm going to investigate at some point this week and see if it can be fixed. It's frustrating that this doesn't match what I'm seeing locally. |
@@ -347,6 +353,9 @@ function tryOnTimeout(timer, start) { | |||
refCount--; | |||
timer[kRefed] = null; | |||
|
|||
if (timer[kHasPrimitive]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might === true
be faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't, hopefully? I think the problem is with symbols but I don't want to do this with a public prop. Maybe @nodejs/v8 can provide some input? Any chance of symbol access getting faster in the future? From what I've seen it's currently quite a bit slower than string props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @bnoordhuis mentioned at some point that it was a bit faster.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder what output turbolizer would give for this, this still doesn't seem right so I can only imagine it would be a polymorphism problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's polymorphism. In the benchmark we don't call this with any values but timer objects. I'm reasonably certain it's the symbol because I've run into this a bunch while working on timers & http2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh whoops, I was thinking of the wrong function
return; | ||
} | ||
|
||
const timerType = typeof timer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typeof
checks are fast IIRC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and I think they are even faster that caching the value like this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if doing the checks and then turning this into an else if
would reduce speculative branching and help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caching typeof
used to be a lot slower than using it inline, at least with Crankshaft, not sure about TurboFan.
// This stores all the known timer async ids to allow users to clearTimeout and | ||
// clearInterval using those ids, to match the spec and the rest of the web | ||
// platform. | ||
const knownTimersById = Object.create(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the keys are going to be numbers, could a holey array be faster?
What's the status on this one? |
Ping @apapirovski it would be great to move this forward. |
@BridgeAR ya, it got held up on performance concerns. Will revisit again. |
This will PR will land one day... maybe... I hope 😞 |
@apapirovski do you think you might find some time to have a look at this some time soon again? |
8ae28ff
to
2935f72
Compare
There's been no further activity, unfortunately. Closing. Can reopen if someone wants to pick it back up |
This allows timers to be matched to numeric Ids and therefore used as keys of an Object, passed and stored without storing the Timer instance. clearTimeout/clearInterval is modified to support numeric/string Ids. Co-authored-by: Bradley Farias <bradley.meck@gmail.com> Co-authored-by: Anatoli Papirovski <apapirovski@mac.com> Refs: nodejs#21152
This allows timers to be matched to numeric Ids and therefore used as keys of an Object, passed and stored without storing the Timer instance. clearTimeout/clearInterval is modified to support numeric/string Ids. Co-authored-by: Bradley Farias <bradley.meck@gmail.com> Co-authored-by: Anatoli Papirovski <apapirovski@mac.com> Refs: #21152 PR-URL: #34017 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This allows timers to be matched to numeric Ids and therefore used as keys of an Object, passed and stored without storing the Timer instance. clearTimeout/clearInterval is modified to support numeric/string Ids. Co-authored-by: Bradley Farias <bradley.meck@gmail.com> Co-authored-by: Anatoli Papirovski <apapirovski@mac.com> Refs: nodejs#21152 PR-URL: nodejs#34017 Backport-PR-URL: nodejs#34482 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Signed-off-by: Denys Otrishko <shishugi@gmail.com>
This allows timers to be matched to numeric Ids and therefore used as keys of an Object, passed and stored without storing the Timer instance. clearTimeout/clearInterval is modified to support numeric/string Ids. Co-authored-by: Bradley Farias <bradley.meck@gmail.com> Co-authored-by: Anatoli Papirovski <apapirovski@mac.com> Refs: #21152 Backport-PR-URL: #34482 PR-URL: #34017 Backport-PR-URL: #34482 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Signed-off-by: Denys Otrishko <shishugi@gmail.com>
This allows timers to be matched to numeric Ids and therefore used as keys of an Object, passed and stored without storing the Timer instance. clearTimeout/clearInterval is modified to support numeric/string Ids. Co-authored-by: Bradley Farias <bradley.meck@gmail.com> Co-authored-by: Anatoli Papirovski <apapirovski@mac.com> Refs: #21152 Backport-PR-URL: #34482 PR-URL: #34017 Backport-PR-URL: #34482 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Signed-off-by: Denys Otrishko <shishugi@gmail.com>
This continues on @bmeck's excellent idea and work in #19683. With their permission, I made some additional changes to improve the performance and fix a memory leak. This way we shouldn't see any (or certainly very minimal) regression in our benchmarks, at least judging by running them locally.
Refs: #19683
Co-authored-by: Bradley Farias bradley.meck@gmail.com
@bmeck I had to give you credit as co-author using github's metadata as it was too much work to rebase the original. Hopefully not a huge deal (but definitely let me know)?
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes