aboutsummaryrefslogtreecommitdiff
path: root/src/js/node/events.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/node/events.js')
-rw-r--r--src/js/node/events.js54
1 files changed, 49 insertions, 5 deletions
diff --git a/src/js/node/events.js b/src/js/node/events.js
index bd79dd3ae..4af75f8e2 100644
--- a/src/js/node/events.js
+++ b/src/js/node/events.js
@@ -92,9 +92,30 @@ const emitWithoutRejectionCapture = function emit(type, ...args) {
if (events === undefined) return false;
var handlers = events[type];
if (handlers === undefined) return false;
-
- for (var handler of [...handlers]) {
- handler.apply(this, args);
+ // Clone handlers array if necessary since handlers can be added/removed during the loop.
+ // Cloning is skipped for performance reasons in the case of exactly one attached handler
+ // since array length changes have no side-effects in a for-loop of length 1.
+ const maybeClonedHandlers = handlers.length > 1 ? handlers.slice() : handlers;
+ for (let i = 0, { length } = maybeClonedHandlers; i < length; i++) {
+ const handler = maybeClonedHandlers[i];
+ // For performance reasons Function.call(...) is used whenever possible.
+ switch (args.length) {
+ case 0:
+ handler.call(this);
+ break;
+ case 1:
+ handler.call(this, args[0]);
+ break;
+ case 2:
+ handler.call(this, args[0], args[1]);
+ break;
+ case 3:
+ handler.call(this, args[0], args[1], args[2]);
+ break;
+ default:
+ handler.apply(this, args);
+ break;
+ }
}
return true;
};
@@ -107,8 +128,31 @@ const emitWithRejectionCapture = function emit(type, ...args) {
if (events === undefined) return false;
var handlers = events[type];
if (handlers === undefined) return false;
- for (var handler of [...handlers]) {
- var result = handler.apply(this, args);
+ // Clone handlers array if necessary since handlers can be added/removed during the loop.
+ // Cloning is skipped for performance reasons in the case of exactly one attached handler
+ // since array length changes have no side-effects in a for-loop of length 1.
+ const maybeClonedHandlers = handlers.length > 1 ? handlers.slice() : handlers;
+ for (let i = 0, { length } = maybeClonedHandlers; i < length; i++) {
+ const handler = maybeClonedHandlers[i];
+ let result;
+ // For performance reasons Function.call(...) is used whenever possible.
+ switch (args.length) {
+ case 0:
+ result = handler.call(this);
+ break;
+ case 1:
+ result = handler.call(this, args[0]);
+ break;
+ case 2:
+ result = handler.call(this, args[0], args[1]);
+ break;
+ case 3:
+ result = handler.call(this, args[0], args[1], args[2]);
+ break;
+ default:
+ result = handler.apply(this, args);
+ break;
+ }
if (result !== undefined && $isPromise(result)) {
addCatch(this, result, type, args);
}