From 66fcbefa7ed0058a6a2b4cbeb749f72ed606b983 Mon Sep 17 00:00:00 2001 From: wwwzbwcom Date: Mon, 30 Aug 2021 00:06:28 +0800 Subject: [PATCH] events: speed up emit by faster null prototype object --- benchmark/events/ee-emit.js | 2 +- lib/events.js | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/benchmark/events/ee-emit.js b/benchmark/events/ee-emit.js index ec35277a9c0214..6743b1701ad9d0 100644 --- a/benchmark/events/ee-emit.js +++ b/benchmark/events/ee-emit.js @@ -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 }) { diff --git a/lib/events.js b/lib/events.js index 557461084631f3..2a2093f047d543 100644 --- a/lib/events.js +++ b/lib/events.js @@ -34,7 +34,6 @@ const { FunctionPrototypeCall, MathMin, NumberIsNaN, - ObjectCreate, ObjectDefineProperty, ObjectDefineProperties, ObjectGetPrototypeOf, @@ -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'); } @@ -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; } @@ -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 @@ -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) @@ -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]; } @@ -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; }