Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

add global listener support #1478

Closed
wants to merge 1 commit into from
@polotek

Adds support for a global event listener using "*".

var ee = new EventEmitter();
ee.on('*', function(event) {
   console.log('global event for ' + event);
});

ee.on('foo', function() {
   console.log('foo');       
})
.on('bar', function() {
   console.log('bar');
});

ee.emit('foo');

setTimeout(function() {
   console.log('after 10 secs');
   ee.emit('bar');
}, 10000);

// output
global event for foo
foo
after 10 secs
global event for baz
baz

This patch is very minimal and uses the same EventEmitter infrastructure. It simply makes "*" a special event name. See this thread for some background. The branch linked there is gone. Replaced by this one (g_event_short).

https://groups.google.com/forum/#!searchin/nodejs/marco$20onevent/nodejs/y3MbKZUKbSU/al89RUn4gfsJ

@polotek

This needs to be run through some benchmarks. But I'm confident that it's pretty low impact. The global funcs are as optimized as the emit function because they're the same. And by passing them is as simple as an if statement.

@hij1nx

-2 -- I think this is extremely destructive to any chance for namespaces or wildcards. Also, this conceptually conflicts with my library.

@mikeal
Owner

how does this destroy the potential for namespaces and other wildcards?

so long as "*" remains a wildcard for all events you can maintain compatibility.

@polotek

Why do people always say no offense right before they say something offensive :)

I think it only seems poorly thought out because of your perspective. To be clear, I'm proposing this patch to core instead of more extensive namespace support. I don't think it's needed. You can do simple namespace with some delimiter on your event name, e.g. on("model:update") on("model:delete"). What you really mean when you say namespacing is glob support like on("model:*"). I don't want that in core.

Yes it messes with your library. But it hasn't been decided that your library is right for node. In fact there's lots of debate there. Lots of people have asked for a simple feature of global listeners. That's what this is. And the point of this was to present it as a counter point to your massive patch. I understand why you're -1 but let's not start attacking each other until we get some more opinions.

To address your point. The "*" event catches literally everything except other "*" events. It even catches the semi-special "newListener" event. Hence the name "global" namespace. Because it only specializes "*" you should be able to sit other namespacing support on top of it. Or ignore it completely with a simple if statement.

The upside is that those people who don't want a bunch of machinery added to core, but would still like to catch all events are covered with this. I think that's a wide area. I've argued against your patch, because I appreciate that core has tried to stay minimal but flexible. I respect your reasoning and I think you make a good case. I just don't fully agree and wanted to get some other options out there.

I can see that this may cause some confusion by suggesting more extensive wildcard support. But honestly that's easily remedied with docs. Or better yet with a simple answer such as Nope, node only supports "*". I'm aware that some people will view this as a silly and somewhat arbitrary limitation. I'm fine with that too. I'd like to hear other opinions.

@hij1nx

@mikeal you misunderstand '*' is any events ON A SINGLE NAMESPACE.
if you want to listen to ANY AND ALL (minus addListener) then you should use onAny

There are fundamental problems to this commit, not only does it conflict with the usage of * in my implementation, but also it pervades the namespace by introducing a un-usable event name '*' and reproduces what onAny does.

e.g. for above:

emitter.onAny(function () {console.log('onAny:', arguments)});
emitter.on('*', function () {console.log('on *:', arguments)});
emitter.emit('foo:bar', 'foobardata');
emitter.emit('foo', 'foodata');

you should see

onAny: { 0: 'foobardata' }
onAny: { 0: 'foodata' }
on *: { 0: 'foodata' }
@polotek

To be clearer. I'm proposing this instead of your patch. So the arguments about namespaces is moot. I don't even have the same definition of namespace as you've chosen. In my mind, wildcards should be hierarchical and not stop at each delimiter. To use your example:

emitter.on('*', function () {console.log('on *:', arguments)});
emitter.emit('foo:bar', 'foobardata');
emitter.emit('foo', 'foodata');

produces

on *: { 0: 'foo:bar', 1: 'foobardata' }
on *: { 0: 'foo', 1: 'foodata' }

This is what many people I've talked to actually want.

Also, if people are using "*" as an event name than I'm 99.99% confident that they are trying to do exactly this. And if they aren't, then they're pretty much going against the accepted meaning of "*" and I have no sympathy for them.

@Marak

Yeah, this patch looks like where we were at a couple of months ago with building EE2.

Why are we going back on progress already made?

@polotek

I'm not trying dismiss EventEmitter 2. I think it's awesome. I just don't want it in core. I don't want node to be that opinionated about how people want to handle events. My counter to Marak's question is EE2 works great in userland, why ar we pushing it or any subset thereof into core? What we're debating now is what's good for core. There's lots of discussion to be had there there and this is my formal entry.

Seriously guys. I know I'm raining on your parade right now. But try to be objective. If your solution is better, you'll win anyway.

@hij1nx

@polotek the reason im kind of upset is because you are confusing the subject and proposing something that will disrupt user-land. My patch goes to great extent to be unobtrusive and not disrupt user-land. You aren't raining on a parade, there is no parade. There are a few simple and very well thought out ideas being proposed. I believe that your intent is to play devils advocate and ensure that community and project is protected. But if your patch is a sincere proposal, Im voting against it because it conflicts useful patterns.

@Marak

It seems you are trying to make a change in good-faith, but are not understanding the repercussions of your actions.

If you implement an improper half-step ( this patch ), it will deter progress in the future by locking developers into an API which cannot be easily changed.

@Marak

My counter to Marak's question is EE2 works great in userland, why ar we pushing it or any subset thereof into core?

This is not a subset, it's not well thought out, and it's going to cause problems ( even with using EE2 in user-land ).

@mikeal
Owner

why can't you just make "*" be "all events" and use "*." syntax for listening to only the top level namespace?

@hij1nx

also @polotek, i hope we're friends enough for me to have handed that "no offense" comment back to you, you totally started that =)

@hij1nx

@mikeal, why have anything at all? why not keep core sparse?

@hij1nx

@mikeal also, if * was to become "everything" how would you differentiate a namespace with a single space?

@mikeal
Owner

your argument can't be that this disrupts a userland module that extends the core EventEmitter API.

core breaks compatibility whenever it wants to. welcome to node.js :)

let's all back up a second. this patch itself doesn't end the discussion about more features on EventEmitter.

all it is:

  • add support for listening to all events
  • the API for listening to all events is listening for "*"
  • the first argument to a global listener is the event name.

i like that API, i like it a lot more than the onAny() API.

if accepted this just means that you'll need to find a new syntax for listening for events that are only in the top level namespace.

@indexzero

-1 There are a couple of issues I see here:

  • This breaks the semantic of event listener functions through introduction of special strings and not method names. Specifically I am talking about:
  ee.on('*', function (event, arg1, arg2 /*, ... argN */) {

  });

vs.

  ee.on('any-other-event-ever-no-matter-what', function (arg1, arg2 /*, ... argN */) {

  });

It is overly confusing to me to add on additional semantics to a callback function just because you passed in "special" arguments to the method. I much prefer the concept of this.event that was introduced in EE2.

@polotek why have a special method signature for "*" events?

@mikeal
Owner

an alternative is to do.

ee.current = name

and set to null at the end of emit()

i'm starting to agree on the special method signature. when we're using the same .on() method for the listener it seems a little weird.

@indexzero

@mikeal Going to have to agree to disagree here. I see consistency as the key; a special method signature would necessitate a separate method imo.

@tmpvar

-1, lets go all out or not at all

@mikeal
Owner

@indexzero i must not have been clear, i'm agreeing with you :)

@indexzero

@mikeal OH. How did I not get that? lol

@polotek

@hij1nx We're absolutely cool man. No worries.

@Marak EE2 will have to (and should) change with this yes. But it will also provide a middle ground for people who don't want absolutely everything. Why is that bad? Also you need to elaborate on how this will deter progress.

I still haven't seen any concrete examples of how this is bad besides the fact that it doesn't fit with some people's vision.

Also, the idea of listening to only the top level namespace doesn't make any sense to me. Why is that method better than keeping the wildcards hierarchical? And more so, why should I have to agree with you if I don't want to do it that way? In my mind that's the beauty of the separation between core and userland.

@jvduf

What's the argument against onAny()? It stupid simple...

@jvduf
  • Adding support for listening to all events in core +1.
  • Doing this by using a reserved event name to listen for any event and using special arguments to listen for "non any" events with a *? No, not convinced by the arguments here. I am against reserving event names or using special arguments.

Why not go for .onAny()? Haven't seen any arguments against that...

Reasons to go for .onAny():

  1. It's simple. You listen to any event. No need for special arguments for '*' events. No explanation needed in docs:
    .on(event, fn) = fire fn on specified event
    .onAny(fn) = fire fn on any event

  2. Leaves the possibility open for namespaced events. Currently there's a big debate going on about this and we don't know where it's going. Using .onAny() gives everybody what they want: listening for any event, stupid simple, leaves options open for namespaced events if the discussion turns out to be in favor of it. If not we can still all live happily ever after with the onAny() listener that listens to any event.

@hij1nx

Unfortunately this thread is split into two threads across your patch and mine.

@jvduf, @polotek, methods are self describing where as syntax is not. We may have our own opinions about what syntax looks better, but how does this look to someone less familiar to the subject? A method is painfully obvious, take the *Sync methods for instance.

@polotek

Re: the method signature. This doesn't hold water either. This is exactly the semantics of eventemitter. You listen on a name. And the handler function receives any arguments that the emitter wants to pass to you. It's no different from this.

on('data', function(chunk) {})

It's node providing a special semantic that gives you the additional data you need in the form of parameters. Using this.event actually seems more like an unnecessary deviation from semantics. Also, I'm aware that the special semantics on "data" event only applies to net or fs streams. But that's a different discussion. Right now if I decided to provide a custom lib that returned an emitter but didn't pass the data as the first parameter. How confusing would that be?

It seems the real objection here is having "*" be special. More on that in a sec.

@polotek
"why not keep core sparse?"

Exactly. In my opinion, a good global listener is the only thing you should need to put extensions on top of the base event emitter. This part of your patch is the important part.

polotek@f71bbee

That's all of your wildcard support. Except you've done a few things that I don't agree with.

  • Added a bunch of unnecessary stuff to core; search trees, a hard dependency on the constructor, etc.
  • "deterred progress" by having node choose a blessed version of wild card support
  • Added your own potential name collisions with things like the "wildcard" option. Now if I want do my own wildcard implementation I have to watch out for that.
  • When wildcard is activated, you are completely overtaking the listener array. Now if I get an event emitter from some library and they've activated wildcards, I have to expect different semantics. It's one thing for this to be a possibility if someone's using EventEmitter2, but quite another if it's in core and I have to worry about it literally anywhere.
  • Added more surface area to the api. See more on this below.

@mikeal had a similar idea about having global listeners be completely separate. I wasn't completely opposed to that and I actually worked up a patch like that as well. It's similar to yours without the wildcards. But has a few minor semantic differences from this "*" implementation. It's in my g_event_full branch.

There are a few reasons why I prefer my version over that.

  • It uses the existing emit infrastructure, which has been tuned to within an inch of it's life. As soon as you separate out global listeners, you can't avoid duplicating this code.
  • It doesn't require lots of separate methods for managing global listeners. You can see them easily in the _events object just like everything else. You can get them with listeners("*"). kill them with removeListeners, etc.
  • It doesn't prevent or override any of the existing semantics of eventemitters. Even if I put wildcard support on top of this, it might look something like this.

    function EventEmitter2() {
    EventEmitter.apply(this, arguments);
    this.on('*', function(type) {
    var handlers = searchForWildCards(type);
    // Here's your list of additional handlers, execute them, forward args
    });
    }

or maybe something less intrusive

require('wildcards').enable(myEmitter);
myEmitter.on('foo.*', function() {
   console.log('Holy crap it works!');
});

In your patch, all of those things add a maintenance burden in a very hot code path. That is a concern for this patch as well. I do plan to do the benchmarking homework.

This patch enables lots of things at the expense of only introducing one more special thing. The star name. Which I think is pretty much globally accepted to mean "everything". The chance of collision is much smaller than either your patch or my other one.

Even if you don't like passing the type to the handler and you want to go with this.event, that doesn't change this much.

@jamesonjlee

EE2 introduces two special things, wildcard and onAny, albeit they overlap when you don't use namespace.

I do agree, maintenance for EE will be difficult, since through major rewrites "almost" everyone involved had to sit in a code review to understand how the new outline was functioning.

Even if you don't like passing the type to the handler and you want to go with this.event, that doesn't change this much.

I preferred this, but the core team was like waaaa this is going to break EVERYTHING

@tj
tj commented

I think you're right @polotek, it's probably good enough to facilitate extending the core EventEmitter for now, at least until/if node core adopts this sort of pattern matching for IPC etc.

@hij1nx

"unnecessary stuff to core";

Technically all of this is unnecessary. New features are usually unnecessary.

a hard dependency on the constructor, etc.

There is no hard dependencies, its exactly parity to event emitter, see criticism for this in original patch discussion for micro optimization.

"deterred progress" by having node choose a blessed version of wild card support.

By this logic we have already deterred progress by implementing the Event Emitter pattern as opposed to another event pattern.

"Added your own potential name collisions with things like the "wildcard" option."
So if you want to make a wrapper around net, you can't use the option "type". If you think wildcard has a high potential for collision (which in my opinion is far fetched) I would say it can be renamed to something more appropriate.

Added more surface area to the api.

By a nominal amount for which the expense does not outweigh the return.

When wildcard is activated, you are completely overtaking the listener array. Now if I get an event emitter from some library and they've activated wildcards, I have to expect different semantics. It's one thing for this to be a possibility if someone's using EventEmitter2, but quite another if it's in core and I have to worry about it literally anywhere.

You should never depend on internal/private members such as _events to provide insights into the characteristics or behaviors of a class/function. We have methods such as listeners which allows our implementations to change as needed and not break our programs.

Anyway, the entire premise of your patch favors sparsity. you favor a weak implantation of wildcards over a complete implantation. I'm pretty sure the next feature request after seeing ee.on('*', f); is going to be "I'd like to doee.on('*bla', f);"

@hij1nx

I've changed my mind. I agree that ee.emit('*'); is good. but I don't like this patch. this patch is simply a performance loss.

@indexzero

I'm still -1 on the "*" string. If this goes in, I think that .onAny() is a more consistent API semantic given the difference in the callback method signatures.

@polotek

@hij1nx and the answer to that request will be "no".

Also, this is not a weak implementation of wildcards. It's an implementation of global listeners that happens to use "*" because I think it makes sense. It's also the minimum feature you need in order to implement wildcards without wrapping emit(). I was frustrated by how many use cases came up that required that. Even to the point where even core guys were telling people to do it because there was no other option.

We are disagreeing on levels of simplicity. We have deterred progress on another event pattern. But it was necessary because node core had to choose one to use. That can't be helped. This can because core doesn't need it for anything whatsoever. I have almost always been an advocate of making it very difficult for things to get into core. I will continue to do so, because it's a slippery slope. If we follow your arguments, then as long as you structure things so it doesn't make node slower, we should drop in all manner of things. Why have you chosen this particular line between what goes in core and what doesn't?

However, I do believe in having the core api provide the minimum set of low level features that are necessary for innovation on top of it. It sounds like you think that should include everything in your patch. Obviously I disagree.

@tj
tj commented

@indexzero good point, I'm not a fan of that part, but {un,on}Any is awkward, I agree though the sig difference is not too great. Sometimes I wish we had Event type objects with arbitrary props instead of varadic sigs

@tj
tj commented

it could be this.event but that's lame/awkward too, it's all awkward :D

@chjj

I'm confused by the code itself. Why the for loop? Is it faster? Why not do something like:

if (type !== globalType) {
  if (this._events[globalType]) {
    var args = slice.call(arguments);
    args.unshift(globalType);
    this.emit.apply(this, args);
  }
}

I imagine it would be more performant, and I think performance is really important here given that it could be executed for every event emitted.

(Other than that, I'm more comfortable with this than I am namespaces, and I kind of like the look more than onAny.)

@hij1nx

@polotek

"because I think it makes sense"

This is not a very strong argument.

Also, this is not a weak implementation of wildcards. It's an implementation of global listeners

Your juggling semantics. Thats also called "clowning"

It's also the minimum feature

I think its myopic. Dealing in tiny pieces can lead to disorganization in the bigger picture.

Why have you chosen this particular line between what goes in core and what doesn't?

According to your logic, both patches should not go in.

@hij1nx

@polotek you have convinced me that nothing should go into core except my performance optimizations.

@hij1nx

@chjj that would seem more efficient, but the arguments object is tricky, crankshaft is equipped with duel compilers... which according to Vyacheslav Egorov, "simple non-optimizing that can handle all existing language constructs but usually produces quite an inefficient code (e.g. does not try to do a register allocation, just caches top of the expression stack in the register) and optimizing one that does not handle all language constructs and tries to predict program behavior (mostly types of values) based on type feedback collected during execution of non-optimized code. Before V8 switched to Crankshaft it relied on a single (almost :-)) compiler known classical or virtual frame. Code produced but will in most cases beat non-optimized code but will be beaten by an optimized one." see the full article here... https://plus.google.com/111090511249453178320/posts/ikjTyY6UKcE

@polotek

@chjj I'm copying the args and then adding the type as the first arg before firing the global listener. I think this makes sense. It's not a change in signature as some people think. It's the right signature for this type of event. See my explanation above. The thing people seem to be missing here is that the * listener shouldn't emitted explicitly by users. And even if they do, they need to pass a type to say something about what they're broadcasting right?

@hij1nx

@polotek, @chjj is writing the code adequately from a historical perspective. The reason you are writing the code as you are is because of the article that i cited.

@polotek

@hij1nx It sounds like you're getting frustrated because you haven't convinced me to change my mind. That's unfortunate.

I'm not juggling the semantics of "a wildcard implementation". Instead you're denying the distinction because it doesn't help your case. If you took out wildcards from your patch and only had the "onAny" stuff, would that be a weak wildcards implementation? Because that's what this is. It just looks different. If you do think they're the same, then you should kill your onAny stuff and just support "*" as global, because it fits with the other constructs you've built in wildcards. That's what I would expect. But you can't do that because turning wildcards on at all changes the behavior. Just sayin.

@hij1nx

@popotek wa!? not at all, at this point i agreed with you! dont start to troll me.

@chjj

@polotek, I'm not disputing the behavior at all. I think it's fine.

@hij1nx, yeah, I've read bits and pieces on the v8 mailing list about the speed hazards of the arguments object. I was under the impression that, at least slicing arguments, was eventually optimized though?

@polotek

@chjj You're right, I didn't read what you put down carefully enough. My apologies. @hij1nx has it right. If you look at the rest of the file, things are done this way for performance.

@hij1nx

If you took out wildcards from your patch and only had the "onAny" stuff, would that be a weak wildcards implementation?

no because its a disparat, self-describing method and makes no syntactical impositions.

@hij1nx

@polotek in case you missed it i agreed with you, i like ee.on('*'); at first i didnt, now i do. Ask me why.

@chjj

@hij1nx, I just wrote a small benchmark, and it confirmed my suspicions that slicing the arguments is a bit faster than a for (using polotek's exact code). (Granted, I'm not exactly sure how accurate that benchmark is or what optimizations v8 is performing on it behind the scenes.)

https://gist.github.com/1133253

@hij1nx

@chjj, ummm.............................. please run your tests using benchmarkjs.com and jsperf.com and using node make test, you simple benchmark is simply too simple to work properly =)

@chjj

@hij1nx, right, I agree, which is why I conceded it's possible inaccuracy.

@hij1nx

This is something that no one has touched on yet. And its pretty much pales any argument made so far.

/usr/lib/nvidia-current/xorg/xorg is an array divided by the / delimiter.

so for example rm -rf /usr/lib/nvidia-current/*, in posix * is greedy. since node is modled after posix APIs, i've decided that ee.on('*'); is valid. however, @polotek's implementation is inefficient, any additional expressions on top of an unoptimized core codebase must be a performance loss. I would be happy to break my commit into parts with the only addition being ee.on('*', f).

@polotek

@hij1nx Sorry, I thought you were being facetious when you said you agreed :) Yes the greedy nature of "*" is what I've been getting at. As for inefficient, I'm not sure how since it uses the same code as everything else. But I await your patch. I'm open to the argument that any wildcard implementation on top of this would be slower than one that is fully integrated.

But it's still a hard sell because core code doesn't need it at all. There are lots of things that would be faster if they were fully integrated. We have to strike that balance between keeping core simple and enabling userland modules to be as fast as possible.

Thanks for staying on with this man. If someone makes a call and this doesn't happen, I'll be fine. I just think it's always good to open up the debate to various options.

@hij1nx

Pfft. You wish you had my point this whole time ;) its still debatable but I'm arguing for benefit of node and not my personal interests, so my perspective may seem schizophrenic. In regards to your patch, the performance loss is simple, it incurs overhead without first optimizing at the correct junctures, if ppl feel strongly about having this feature and only this feature, I would rather it was done without penalty.

@mikeal
Owner

i was talking to @polotek and we realized that this.event and ee.event won't work.

this is the eventemitter instance, so this.event and ee.event are the same thing.

when this happens:

ee.on('one', function () {
  ee.emit('two')    
})
ee.on('one', function () {
  console.log(ee.event)
})

Unless we set and unset the property on every emit() call that will log "two".

@hij1nx

@mikeal @polotek this works in my patch.

@jamesonjlee

fyi, the patch was to rebind before every callback.

@trevnorris
Owner

Seems #1457 was the preferred method for this feature, but not even that has been merged yet. Move to close this pull request.

@bnoordhuis bnoordhuis closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 8, 2011
  1. @polotek

    add global listener support

    polotek authored
This page is out of date. Refresh to see the latest.
View
14 lib/events.js
@@ -36,7 +36,7 @@ EventEmitter.prototype.setMaxListeners = function(n) {
this._events.maxListeners = n;
};
-
+var globalType = '*';
EventEmitter.prototype.emit = function() {
var type = arguments[0];
// If there is no 'error' event listener then throw.
@@ -55,6 +55,18 @@ EventEmitter.prototype.emit = function() {
if (!this._events) return false;
var handler = this._events[type];
+
+ // global event, emit even if there are no type specific handlers
+ if (type !== globalType) {
+ if (this._events[globalType]) {
+ var l = arguments.length;
+ var args = new Array(l+1); // make room to push globalType on the front
+ args[0] = globalType;
+ for (var i = 0; i < l; i++) args[i+1] = arguments[i];
+ this.emit.apply(this, args);
+ }
+ }
+
if (!handler) return false;
if (typeof handler == 'function') {
View
15 test/simple/test-event-emitter-add-listeners.js
@@ -25,12 +25,13 @@ var events = require('events');
var e = new events.EventEmitter();
-var events_new_listener_emited = [];
+var events_new_listener_emitted = [];
+var events_global_listener_emitted = [];
var times_hello_emited = 0;
e.addListener('newListener', function(event, listener) {
console.log('newListener: ' + event);
- events_new_listener_emited.push(event);
+ events_new_listener_emitted.push(event);
});
e.on('hello', function(a, b) {
@@ -40,6 +41,13 @@ e.on('hello', function(a, b) {
assert.equal('b', b);
});
+e.on('*', function(event) {
+ console.log('global');
+ events_global_listener_emitted.push(event);
+ assert.equal('a', arguments[1]);
+ assert.equal('b', arguments[2]);
+});
+
console.log('start');
e.emit('hello', 'a', 'b');
@@ -51,7 +59,8 @@ f.setMaxListeners(0);
process.addListener('exit', function() {
- assert.deepEqual(['hello'], events_new_listener_emited);
+ assert.deepEqual(['hello', '*'], events_new_listener_emitted);
+ assert.deepEqual(['hello'], events_global_listener_emitted);
assert.equal(1, times_hello_emited);
});
View
16 test/simple/test-event-emitter-num-args.js
@@ -24,12 +24,19 @@ var assert = require('assert');
var events = require('events');
var e = new events.EventEmitter(),
- num_args_emited = [];
+ num_args_emitted = [],
+ num_global_args_emitted = [];
e.on('numArgs', function() {
var numArgs = arguments.length;
console.log('numArgs: ' + numArgs);
- num_args_emited.push(numArgs);
+ num_args_emitted.push(numArgs);
+});
+
+e.on('*', function() {
+ var numArgs = arguments.length;
+ console.log('numGlobalArgs: ' + numArgs);
+ num_global_args_emitted.push(numArgs);
});
console.log('start');
@@ -42,7 +49,6 @@ e.emit('numArgs', null, null, null, null);
e.emit('numArgs', null, null, null, null, null);
process.addListener('exit', function() {
- assert.deepEqual([0, 1, 2, 3, 4, 5], num_args_emited);
+ assert.deepEqual([0, 1, 2, 3, 4, 5], num_args_emitted);
+ assert.deepEqual([1, 2, 3, 4, 5, 6], num_global_args_emitted);
});
-
-
View
11 test/simple/test-event-emitter-remove-all-listeners.js
@@ -25,6 +25,8 @@ var events = require('events');
function listener() {}
+function gListener1() {}
+function gListener2() {}
var e1 = new events.EventEmitter();
e1.addListener('foo', listener);
@@ -37,7 +39,14 @@ assert.deepEqual([listener], e1.listeners('bar'));
var e2 = new events.EventEmitter();
e2.addListener('foo', listener);
e2.addListener('bar', listener);
+e2.addListener('*', gListener1);
e2.removeAllListeners();
-console.error(e2);
assert.deepEqual([], e2.listeners('foo'));
assert.deepEqual([], e2.listeners('bar'));
+assert.deepEqual([], e2.listeners('*'));
+
+var e3 = new events.EventEmitter();
+e3.addListener('*', gListener1);
+e3.addListener('*', gListener2);
+e3.removeAllListeners('*');
+assert.deepEqual([], e2.listeners('*'));
View
21 test/simple/test-event-emitter-remove-listeners.js
@@ -25,6 +25,7 @@ var events = require('events');
var count = 0;
+var gcount = 0;
function listener1() {
console.log('listener1');
@@ -41,6 +42,16 @@ function listener3() {
count++;
}
+function globalListener1() {
+ console.log('globalListener1');
+ gcount++;
+}
+
+function globalListener2() {
+ console.log('globalListener2');
+ gcount++;
+}
+
var e1 = new events.EventEmitter();
e1.addListener('hello', listener1);
e1.removeListener('hello', listener1);
@@ -57,5 +68,13 @@ e3.addListener('hello', listener2);
e3.removeListener('hello', listener1);
assert.deepEqual([listener2], e3.listeners('hello'));
+var e4 = new events.EventEmitter();
+e4.on('*', globalListener1);
+e4.removeListener('*', globalListener1);
+assert.deepEqual([], e4.listeners('*'));
-
+var e5 = new events.EventEmitter();
+e5.on('*', globalListener1);
+e5.on('*', globalListener2);
+e5.removeListener('*', globalListener1);
+assert.deepEqual([globalListener2], e5.listeners('*'));
Something went wrong with that request. Please try again.