Skip to content

Commit

Permalink
events: speed up emit by faster null prototype object
Browse files Browse the repository at this point in the history
  • Loading branch information
wwwzbwcom committed Aug 30, 2021
1 parent 449147e commit 66fcbef
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 8 deletions.
2 changes: 1 addition & 1 deletion benchmark/events/ee-emit.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const EventEmitter = require('events').EventEmitter;
const bench = common.createBenchmark(main, {
n: [2e6],
argc: [0, 2, 4, 10],
listeners: [1, 5, 10],
listeners: [0, 1, 5, 10],
});

function main({ n, argc, listeners }) {
Expand Down
22 changes: 15 additions & 7 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const {
FunctionPrototypeCall,
MathMin,
NumberIsNaN,
ObjectCreate,
ObjectDefineProperty,
ObjectDefineProperties,
ObjectGetPrototypeOf,
Expand Down Expand Up @@ -127,6 +126,15 @@ EventEmitter.prototype._maxListeners = undefined;
let defaultMaxListeners = 10;
let isEventTarget;

// We need to create null prototype to prevent internal method like `toString`
// mess with event handling. In current version v8, Object create by
// `ObjectSetPrototypeOf` is much more efficient than `ObjectCreate(null)`
function objectCreateNull() {
const events = {};
ObjectSetPrototypeOf(events, null);
return events;
}

function checkListener(listener) {
validateFunction(listener, 'listener');
}
Expand Down Expand Up @@ -198,7 +206,7 @@ EventEmitter.init = function(opts) {

if (this._events === undefined ||
this._events === ObjectGetPrototypeOf(this)._events) {
this._events = ObjectCreate(null);
this._events = objectCreateNull();
this._eventsCount = 0;
}

Expand Down Expand Up @@ -428,7 +436,7 @@ function _addListener(target, type, listener, prepend) {

events = target._events;
if (events === undefined) {
events = target._events = ObjectCreate(null);
events = target._events = objectCreateNull();
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
Expand Down Expand Up @@ -571,7 +579,7 @@ EventEmitter.prototype.removeListener =

if (list === listener || list.listener === listener) {
if (--this._eventsCount === 0)
this._events = ObjectCreate(null);
this._events = objectCreateNull();
else {
delete events[type];
if (events.removeListener)
Expand Down Expand Up @@ -626,11 +634,11 @@ EventEmitter.prototype.removeAllListeners =
// Not listening for removeListener, no need to emit
if (events.removeListener === undefined) {
if (arguments.length === 0) {
this._events = ObjectCreate(null);
this._events = objectCreateNull();
this._eventsCount = 0;
} else if (events[type] !== undefined) {
if (--this._eventsCount === 0)
this._events = ObjectCreate(null);
this._events = objectCreateNull();
else
delete events[type];
}
Expand All @@ -644,7 +652,7 @@ EventEmitter.prototype.removeAllListeners =
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = ObjectCreate(null);
this._events = objectCreateNull();
this._eventsCount = 0;
return this;
}
Expand Down

0 comments on commit 66fcbef

Please sign in to comment.