Repository: nodejs/node
Pull request: events: optimize EventTarget.addEventListener

```
events/eventtarget-add-remove-abort.js nListener=1 n=100000         ***    223.45 %      ±12.03% ±16.12% ±21.21%
events/eventtarget-add-remove-abort.js nListener=10 n=100000        ***    199.33 %       ±9.42% ±12.63% ±16.65%
events/eventtarget-add-remove-abort.js nListener=5 n=100000         ***    221.94 %       ±8.80% ±11.78% ±15.47%
```

Fixes: https://github.com/nodejs/node/issues/55311

Changed files:
filename: benchmark/events/eventtarget-add-remove-abort.js
patch: @@ -0,0 +1,25 @@
+'use strict';
+const common = require('../common.js');
+
+const bench = common.createBenchmark(main, {
+  n: [1e5],
+  nListener: [1, 5, 10],
+});
+
+function main({ n, nListener }) {
+  const target = new EventTarget();
+  const listeners = [];
+  for (let k = 0; k < nListener; k += 1)
+    listeners.push(() => {});
+
+  bench.start();
+  for (let i = 0; i < n; i += 1) {
+    for (let k = listeners.length; --k >= 0;) {
+      target.addEventListener('abort', listeners[k]);
+    }
+    for (let k = listeners.length; --k >= 0;) {
+      target.removeEventListener('abort', listeners[k]);
+    }
+  }
+  bench.end(n);
+}

filename: benchmark/events/eventtarget-add-remove.js
patch: @@ -2,8 +2,8 @@
 const common = require('../common.js');
 
 const bench = common.createBenchmark(main, {
-  n: [1e6],
-  nListener: [5, 10],
+  n: [1e5],
+  nListener: [1, 5, 10],
 });
 
 function main({ n, nListener }) {

filename: lib/internal/event_target.js
patch: @@ -597,19 +597,40 @@ class EventTarget {
     if (arguments.length < 2)
       throw new ERR_MISSING_ARGS('type', 'listener');
 
-    // We validateOptions before the validateListener check because the spec
-    // requires us to hit getters.
-    const {
-      once,
-      capture,
-      passive,
-      signal,
-      isNodeStyleListener,
-      weak,
-      resistStopPropagation,
-    } = validateEventListenerOptions(options);
-
-    validateAbortSignal(signal, 'options.signal');
+    let once = false;
+    let capture = false;
+    let passive = false;
+    let isNodeStyleListener = false;
+    let weak = false;
+    let resistStopPropagation = false;
+
+    if (options !== kEmptyObject) {
+      // We validateOptions before the validateListener check because the spec
+      // requires us to hit getters.
+      options = validateEventListenerOptions(options);
+
+      once = options.once;
+      capture = options.capture;
+      passive = options.passive;
+      isNodeStyleListener = options.isNodeStyleListener;
+      weak = options.weak;
+      resistStopPropagation = options.resistStopPropagation;
+
+      const signal = options.signal;
+
+      validateAbortSignal(signal, 'options.signal');
+
+      if (signal) {
+        if (signal.aborted) {
+          return;
+        }
+        // TODO(benjamingr) make this weak somehow? ideally the signal would
+        // not prevent the event target from GC.
+        signal.addEventListener('abort', () => {
+          this.removeEventListener(type, listener, options);
+        }, { __proto__: null, once: true, [kWeakHandler]: this, [kResistStopPropagation]: true });
+      }
+    }
 
     if (!validateEventListener(listener)) {
       // The DOM silently allows passing undefined as a second argument
@@ -623,18 +644,8 @@ class EventTarget {
       process.emitWarning(w);
       return;
     }
-    type = webidl.converters.DOMString(type);
 
-    if (signal) {
-      if (signal.aborted) {
-        return;
-      }
-      // TODO(benjamingr) make this weak somehow? ideally the signal would
-      // not prevent the event target from GC.
-      signal.addEventListener('abort', () => {
-        this.removeEventListener(type, listener, options);
-      }, { __proto__: null, once: true, [kWeakHandler]: this, [kResistStopPropagation]: true });
-    }
+    type = webidl.converters.DOMString(type);
 
     let root = this[kEvents].get(type);