-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
lib: reuse default DOMException in AbortController #47908
Conversation
lib/internal/abort_controller.js
Outdated
if (reason === undefined) { | ||
reason = lazyDOMException(); | ||
} |
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.
Would reason ??= lazyDOMException();
also work in here, and in the next usage?
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 so yes! updating this (since benchmark ci is running would pushing a commit interfere with it?)
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.
No, it won't interfere with it. 👍
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.
Done!
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 this is correct, users should be able to supply null
as a reason
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 ok yes reverting
abort(reason = new DOMException('This operation was aborted', 'AbortError')) { | ||
abort(reason) { | ||
if (reason === undefined) { | ||
reason = lazyDOMException(); |
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.
Since we are not creating a new error everytime abort is called, 2 different usages in the code throwing this error, might have a different stack trace. Is this compliant with the spec?
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.
ah good point, not sure about that, one thing we could do maybe is move this lazy loading inside the functions themselves. that should ensure correct trace?
lib/internal/abort_controller.js
Outdated
static abort( | ||
reason = new DOMException('This operation was aborted', 'AbortError')) { | ||
static abort(reason) { | ||
reason ??= lazyDOMException(); |
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 this won’t let users define a null
abort reason. Any reason to use this syntax over what was before? Also it changes the .length
property of the static method from 0
to 1
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.
.length
property? didn't get you
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.
The function's .length
property (controller.abort.length) which is typically not important but in web standards like AbortController it is
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.
Ah ok got it, it expects the reason param now thats why
d2923f0
to
832efd8
Compare
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.
Good work but as others mentioned this means that all the aborts get the same stack trace and it's impossible to figure out where an error came from so the performance benefit is probably not worth the debugging downside of knowing who called ".abort" which is currently possible since the error is captured in .abort
but now becomes impossible IIUC.
(I have no idea just asking) is there maybe a way to recapture the trace and inject the details into the lazy loaded one? |
I think something like Error.captureStackTrace could help? or would it just erase the gains. |
I'm afraid creating the error and capturing the stack is the expensive part so I'm not sure, it may be worth while to optimize DOMException itself |
It may be fast to not create the DOMException in |
IIUC it is for reason only |
Hey so in 5259cbe I did the following
'use strict';
const ac1 = new AbortController();
ac1.signal.addEventListener('abort', () => {
console.log(ac1.signal.reason);
});
const ac2 = new AbortController();
ac2.signal.addEventListener('abort', () => {
console.log(ac2.signal.reason);
});
function abortThis(controller) {
controller.abort();
}
function abortThis2(controller) {
controller.abort();
}
setTimeout(() => {
abortThis(ac1);
setTimeout(() => {
abortThis2(ac2);
}, 100);
}, 100); On normal node trace looks like this DOMException [AbortError]: This operation was aborted
at new DOMException (node:internal/per_context/domexception:53:5)
at AbortController.abort (node:internal/abort_controller:331:18)
at abortThis (/Users/debadreechatterjee/Documents/Personal/node/test.js:11:14)
at Timeout._onTimeout (/Users/debadreechatterjee/Documents/Personal/node/test.js:17:3)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
DOMException [AbortError]: This operation was aborted
at new DOMException (node:internal/per_context/domexception:53:5)
at AbortController.abort (node:internal/abort_controller:331:18)
at abortThis2 (/Users/debadreechatterjee/Documents/Personal/node/test.js:14:14)
at Timeout._onTimeout (/Users/debadreechatterjee/Documents/Personal/node/test.js:19:5)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7) On this PR DOMException [AbortError]: This operation was aborted
at AbortController.abort (node:internal/abort_controller:352:7)
at abortThis (/Users/debadreechatterjee/Documents/Personal/node/test.js:11:14)
at Timeout._onTimeout (/Users/debadreechatterjee/Documents/Personal/node/test.js:17:3)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7)
DOMException [AbortError]: This operation was aborted
at AbortController.abort (node:internal/abort_controller:352:7)
at abortThis2 (/Users/debadreechatterjee/Documents/Personal/node/test.js:14:14)
at Timeout._onTimeout (/Users/debadreechatterjee/Documents/Personal/node/test.js:19:5)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7) and the performance benefit still seems to exist, although not as impressive as the initial one: confidence improvement accuracy (*) (**) (***)
events/abortcontroller-abort.js n=1000000 *** 20.64 % ±3.77% ±5.01% ±6.53%
Be aware that when doing many comparisons the risk of a false-positive result increases.
In this case, there are 1 comparisons, you can thus expect the following amount of false-positive results:
0.05 false positives, when considering a 5% risk acceptance (*, **, ***),
0.01 false positives, when considering a 1% risk acceptance (**, ***),
0.00 false positives, when considering a 0.1% risk acceptance (***) wdyt @benjamingr |
Wouldn't that replace the stack trace on earlier references to the error "under the hood" since it's the same reference? |
Ah oh no yes, I am not thinking straight 😓😓 I guess then this a dead end 😕 |
Probably no other way, for now, maybe we could optimize DOMException, I am closing this for now, If there are any other ideas I think we can discuss on this PR thread |
Similar to #46086 have reused the default DOMException we throw when calling
ac.abort()
, so far the tests dont break and the benchmark added in this PR show good improvementBenchmark results:
Refs: #46086
Refs: nodejs/performance#44