-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
events: pass the original listener added by EventEmitter#once to the removeListener handler #6394
Conversation
Why would we go through the trouble of trying to prevent that? Using the |
I’d say by explicitly invoking the listener in the |
@addaleax But as the output showed in the first code example, no matter invoking the |
I have to admit, I find the PR title here a bit confusing then. I think a much cleaner solution (and more aligned with user expectations?) would be to pass the original listener which has been passed to |
@addaleax It's a better solution, i will change the code. |
cffb713
to
b12c2ac
Compare
@addaleax Hey bro, I've changed the code and the content of this PR. Now the user will get the original listener which added by |
I like the change, but would like to head other’s opinions on this. I think this could be considered a bugfix, because this is how I’d understand the documentation (if I didn’t know how
Appreciate you not wanting to be formal, but I’m definitely not a bro, for more than one reason. :) |
I think so, too : = ) |
This makes sense, but could you add tests. |
@cjihrig 👌 |
b12c2ac
to
fa40a5a
Compare
@cjihrig Already added : = ) |
I had no idea the original function wasn't passed, I'd expect the listener passed to once to be the listener passed in the removeListener event! |
@sam-github It will be, if this PR merged. |
|
||
const listener5 = () => {}; | ||
const listener6 = common.mustCall((eventName, listener) => { | ||
assert.deepStrictEqual(eventName, 'hello'); |
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.
Both assertions can be assert.strictEqual()
.
LGTM pending comments and CI. Are we classifying this as semver major or patch? I'd lean toward patch, but this could potentially break things. |
fa40a5a
to
d26733d
Compare
Yeah, I think this breaks only code that is already broken. So, leaning towards patch, too. |
I lean towards patch, too. |
Related (covers the same ground): #5564 |
Seems that the solution code in this PR is more lightweight and harmless ? |
Look into #5564 line 338: change to
seems more readable. |
const e7 = new events.EventEmitter(); | ||
|
||
const listener5 = () => {}; | ||
const listener6 = common.mustCall((eventName, listener) => { |
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 be clearer to just inline listener6
with the removeListener
line below instead of creating a separate decl for it
LGTM with a nit. Pending CI of course. |
Looks good, landing |
When removing a `once` listener, the listener being passed to the `removeListener` callback is the wrapper. This unwraps the listener so that `removeListener` is passed the actual listener. PR-URL: #6394 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
Landed in 706778a |
Shouldn't this be tagged as |
Yes. Done. |
Wait, I take that back. We talked about this the other day. Most people (myself included) were leaning toward patch. I can see how it would be a major though. |
That was brought up a few comments up: #6394 (comment) |
@mscdex ... it could be see discussion here #6394 (comment) ... the existing behavior can be rightfully considered to be a bug and this is just a fix. I'm -1 on it being semver-major. |
@mscdex ... to be on the safe side we can hold off on pulling this back to v5 or v4 for a while in case there are any regressions caused. |
When removing a `once` listener, the listener being passed to the `removeListener` callback is the wrapper. This unwraps the listener so that `removeListener` is passed the actual listener. PR-URL: #6394 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
When removing a `once` listener, the listener being passed to the `removeListener` callback is the wrapper. This unwraps the listener so that `removeListener` is passed the actual listener. PR-URL: nodejs#6394 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
do you think it is about time ot backport @nodejs/lts? |
@nodejs/lts @nodejs/ctc thoughts on this being backported? |
I think its reasonable to backport |
When removing a `once` listener, the listener being passed to the `removeListener` callback is the wrapper. This unwraps the listener so that `removeListener` is passed the actual listener. PR-URL: #6394 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
Checklist
Description of change
We use the
_onceWrap
function to wrap the listener added byEventEmitter#once
, and use the flagfired
inside to make sure the listener will only be called once, including the calling in theremoveListener
event:But by explicitly invoking the listener in the removeListener handler the user expresses a pretty strong intent that the listener should be called. By now we can use a
listener.listener
trick to archive this:But those who have not read the the code of
lib/events.js
should not know this trick at all, and using tricks is alway not a good way. so this PR is to pass the original listener added byEventEmitter#once
to theremoveListener
handler: