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

events: add eventNames() method #5617

Closed
wants to merge 6 commits into from
Closed

Conversation

jasnell
Copy link
Member

@jasnell jasnell commented Mar 9, 2016

Pull Request check-list

Please make sure to review and check all of these items:

  • Does make -j8 test (UNIX) or vcbuild test nosign (Windows) pass with
    this change (including linting)?
  • Is the commit message formatted according to [CONTRIBUTING.md][0]?
  • If this change fixes a bug (or a performance problem), is a regression
    test (or a benchmark) included?
  • Is a documentation update included (if this change modifies
    existing APIs, or introduces new ones)?

NOTE: these things are not required to open a PR and can be done
afterwards / while the PR is open.

Affected core subsystem(s)

events

Description of change

Per #1817, there are many modules
that currently abuse the private _events property on EventEmitter.
One of the ways it is used is to determine if a particular event is
being listened for. This adds a simple eventNames() method that
returns an array of the events with currently registered listeners.

/cc @ChALkeR

@jasnell jasnell added events Issues and PRs related to the events subsystem / EventEmitter. semver-minor PRs that contain new features and should be released in the next minor version. labels Mar 9, 2016
@jasnell
Copy link
Member Author

jasnell commented Mar 9, 2016

@ChALkeR ... currently this returns an Array... given the various use cases that I've seen, however, the listenerCount API is typically sufficient. I implemented this quickly given your discussion in #1817. Do you still feel this is necessary?

@mscdex
Copy link
Contributor

mscdex commented Mar 9, 2016

-1 for the reason you stated: listenerCount() can already handle most needs for a method like this.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 9, 2016

@mscdex listenerCount() is not enough in some cases, see, for example, the ultron module from #1817. I will prepare a list of other modules that do something like that.

@jasnell

One of the ways it is used is to determine if a particular event is being listened for.

That usecase is covered by the listenerCount(type) method, iterating over all present event listeners isn't.

@mscdex
Copy link
Contributor

mscdex commented Mar 9, 2016

FWIW if such a mechanism were to be added, I'd prefer something like just events() to match our existing listeners(), but the problem would be naming clashes if (many) modules use that same property name.

@jasnell
Copy link
Member Author

jasnell commented Mar 10, 2016

@mscdex .. possible name clashes is exactly why I used listEvents instead of just events... it's a less obvious choice.

@ChALkeR ... couldn't the iterating over all present listeners be handled by listening for the 'newListener' and 'removeListener' events? Sure, it requires a bit more work but it's not too difficult.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 10, 2016

@jasnell Not if something receives an eventemitter that already has some listeners after those listeners were attached.

@jasnell
Copy link
Member Author

jasnell commented Mar 11, 2016

@ChALkeR ... good point. Can you do a scan of existing modules to see if using events() would cause any conflicts?

@mscdex
Copy link
Contributor

mscdex commented Mar 11, 2016

or even something like eventNames(). IMHO listEvents() sounds like a ("action") function that will print the event names to the console or something.

@jasnell
Copy link
Member Author

jasnell commented Mar 11, 2016

+1 to eventNames()

Per nodejs#1817, there are many modules
that currently abuse the private `_events` property on EventEmitter.
One of the ways it is used is to determine if a particular event is
being listened for. This adds a simple `listEvents()` method that
returns an array of the events with currently registered listeners.
@jasnell
Copy link
Member Author

jasnell commented Mar 12, 2016

@ChALkeR @mscdex ... updated to use eventNames(). PTAL

if (events) {
return Object.getOwnPropertyNames(events).concat(
Object.getOwnPropertySymbols(events));
} else return [];
Copy link
Contributor

Choose a reason for hiding this comment

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

Having the return [] on the next line would be more readable IMHO

@jasnell
Copy link
Member Author

jasnell commented Mar 12, 2016

@mscdex ... updated!

@@ -436,6 +436,15 @@ function listenerCount(type) {
return 0;
}

EventEmitter.prototype.eventNames = function() {
const events = this._events;
Copy link
Contributor

Choose a reason for hiding this comment

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

minor nit: this can go inside the if block now.

@jasnell
Copy link
Member Author

jasnell commented Mar 12, 2016

@mscdex ... fixed!

@mscdex
Copy link
Contributor

mscdex commented Mar 12, 2016

@@ -295,6 +295,24 @@ they were registered, passing the supplied arguments to each.

Returns `true` if event had listeners, `false` otherwise.

### emitter.eventNames()
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be Names? Why not just events?

Copy link
Member

Choose a reason for hiding this comment

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

Discussed above. Two reasons:

  1. This is less likely to cause conflicts with modules extending EventEmitter.

  2. This is more reasonable name because it correctly describes what this method actually does — it returns the list of event names for the registered event listeners. _events, for an example, is an object that stores all listeners (grouped by event name).

    It would be easier to understand what the code that uses this method does without navigating to the docs this way.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ChALkeR I am really sorry. I straight away started with the code. It makes sense. Thanks for explaining.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 13, 2016

@jasnell, @mscdex eventNames is used by some of the modules, but I can't atm give an estimate of how many of those (if any) are properties of eventemitter objects.

Quick grep for \.eventNames[^a-zA-Z_]: https://gist.github.com/ChALkeR/8ff143bd3189b9026d7e.

Sorry for the delay.

@ChALkeR
Copy link
Member

ChALkeR commented Mar 13, 2016

Actually, the usage looks low.
The new name LGTM (and the PR itself LGTM too).

This is technically a semver-minor, but I would prefer this to be merged in a major release (i.e. 6.0).

@ChALkeR ChALkeR mentioned this pull request Mar 13, 2016
3 tasks
@mscdex
Copy link
Contributor

mscdex commented Mar 13, 2016

@jasnell It looks like at least one existing test needs to be updated: test-event-emitter-method-names.js

I think I agree with @ChALkeR about landing this in 6.0.

@thefourtheye
Copy link
Contributor

LGTM

@jasnell
Copy link
Member Author

jasnell commented Mar 13, 2016

Landing as a major SGTM. Always good to be safe. I'll take a look at the
test later on today.
On Mar 13, 2016 4:13 AM, "Brian White" notifications@github.com wrote:

@jasnell https://github.com/jasnell It looks like at least one existing
test needs to be updated: test-event-emitter-method-names.js

I think I agree with @ChALkeR https://github.com/ChALkeR about landing
this in 6.0.


Reply to this email directly or view it on GitHub
#5617 (comment).

@jasnell jasnell changed the title events: add listEvents() method events: add eventNames() method Mar 14, 2016
@jasnell
Copy link
Member Author

jasnell commented Mar 14, 2016

@jasnell
Copy link
Member Author

jasnell commented Mar 14, 2016

CI is green with on apparently unrelated failure.

@jasnell
Copy link
Member Author

jasnell commented Mar 14, 2016

semver-minor but marking as don't land on v5 or v4 just to be extra cautious per #5617 (comment) and #5617 (comment)

@ChALkeR
Copy link
Member

ChALkeR commented Mar 15, 2016

@jasnell Thanks!

jasnell added a commit that referenced this pull request Mar 15, 2016
Per #1817, there are many modules
that currently abuse the private `_events` property on EventEmitter.
One of the ways it is used is to determine if a particular event is
being listened for. This adds a simple `eventNames()` method that
returns an array of the events with currently registered listeners.

PR-URL: #5617
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
@jasnell
Copy link
Member Author

jasnell commented Mar 15, 2016

Landed in b6e3fa7

if (this._eventsCount > 0) {
const events = this._events;
return Object.keys(events).concat(
Object.getOwnPropertySymbols(events));
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we check if the symbol property is enumerable events.propertyIsEnumerable(symbol) and add it to the array only if it is?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
events Issues and PRs related to the events subsystem / EventEmitter. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants