This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Optimize event emitter for single listener

  • Loading branch information...
1 parent c1613e6 commit 2c7cbbc1b08a1c5bb8ccee3fcb6dc0145d6f1a70 @ry ry committed Mar 12, 2010
Showing with 68 additions and 23 deletions.
  1. +41 −15 src/node.js
  2. +27 −8 src/node_events.cc
View
@@ -170,37 +170,63 @@ var eventsModule = createInternalModule('events', function (exports) {
// process.EventEmitter is defined in src/events.cc
// process.EventEmitter.prototype.emit() is also defined there.
process.EventEmitter.prototype.addListener = function (type, listener) {
- if (listener instanceof Function) {
- if (!this._events) this._events = {};
- if (!this._events.hasOwnProperty(type)) this._events[type] = [];
- // To avoid recursion in the case that type == "newListeners"! Before
- // adding it to the listeners, first emit "newListeners".
- this.emit("newListener", type, listener);
+ if (!(listener instanceof Function)) {
+ throw new Error('addListener only takes instances of Function');
+ }
+
+ if (!this._events) this._events = {};
+
+ // To avoid recursion in the case that type == "newListeners"! Before
+ // adding it to the listeners, first emit "newListeners".
+ this.emit("newListener", type, listener);
+
+ if (!this._events[type]) {
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ } else if (this._events[type] instanceof Array) {
+ // If we've already got an array, just append.
this._events[type].push(listener);
+ } else {
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
}
+
return this;
};
process.EventEmitter.prototype.removeListener = function (type, listener) {
- if (listener instanceof Function) {
- // does not use listeners(), so no side effect of creating _events[type]
- if (!this._events || !this._events.hasOwnProperty(type)) return;
- var list = this._events[type];
- if (list.indexOf(listener) < 0) return;
- list.splice(list.indexOf(listener), 1);
+ if (!(listener instanceof Function)) {
+ throw new Error('removeListener only takes instances of Function');
}
+
+ // does not use listeners(), so no side effect of creating _events[type]
+ if (!this._events || !this._events[type]) return this;
+
+ var list = this._events[type];
+
+ if (list instanceof Array) {
+ var i = list.indexOf(listener);
+ if (i < 0) return this;
+ list.splice(i, 1);
+ } else {
+ this._events[type] = null;
+ }
+
return this;
};
process.EventEmitter.prototype.removeAllListeners = function (type) {
// does not use listeners(), so no side effect of creating _events[type]
- if (!type || !this._events || !this._events.hasOwnProperty(type)) return this;
- this._events[type].length = 0;
+ if (!type || !this._events || !this._events[type]) return this;
+ this._events[type] = null;
};
process.EventEmitter.prototype.listeners = function (type) {
if (!this._events) this._events = {};
- if (!this._events.hasOwnProperty(type)) this._events[type] = [];
+ if (!this._events[type]) this._events[type] = [];
+ if (!(this._events[type] instanceof Array)) {
+ this._events[type] = [this._events[type]];
+ }
return this._events[type];
};
View
@@ -50,15 +50,11 @@ static bool ReallyEmit(Handle<Object> self,
Local<Object> events = events_v->ToObject();
Local<Value> listeners_v = events->Get(event);
- if (!listeners_v->IsArray()) return false;
- Local<Array> listeners = Local<Array>::Cast(listeners_v);
+ Local<Function> listener;
- for (unsigned int i = 0; i < listeners->Length(); i++) {
- HandleScope scope;
-
- Local<Value> listener_v = listeners->Get(Integer::New(i));
- if (!listener_v->IsFunction()) continue;
- Local<Function> listener = Local<Function>::Cast(listener_v);
+ if (listeners_v->IsFunction()) {
+ // Optimized one-listener case
+ Local<Function> listener = Local<Function>::Cast(listeners_v);
TryCatch try_catch;
@@ -68,6 +64,29 @@ static bool ReallyEmit(Handle<Object> self,
FatalException(try_catch);
return false;
}
+
+ } else if (listeners_v->IsArray()) {
+ Local<Array> listeners = Local<Array>::Cast(listeners_v);
+
+ for (unsigned int i = 0; i < listeners->Length(); i++) {
+ HandleScope scope;
+
+ Local<Value> listener_v = listeners->Get(Integer::New(i));
+ if (!listener_v->IsFunction()) continue;
+ Local<Function> listener = Local<Function>::Cast(listener_v);
+
+ TryCatch try_catch;
+
+ listener->Call(self, argc, argv);
+
+ if (try_catch.HasCaught()) {
+ FatalException(try_catch);
+ return false;
+ }
+ }
+
+ } else {
+ return false;
}
return true;

0 comments on commit 2c7cbbc

Please sign in to comment.