From 996a87b168ea22592313803d1d068065e438787f Mon Sep 17 00:00:00 2001 From: Benjamin Gruenbaum Date: Mon, 9 Nov 2020 18:49:19 +0200 Subject: [PATCH] fix(op_crates/web): handler order when reassign (#8264) --- op_crates/web/02_abort_signal.js | 27 +++++++++++++++++++------- op_crates/web/abort_controller_test.js | 18 +++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/op_crates/web/02_abort_signal.js b/op_crates/web/02_abort_signal.js index 53745c52ba..5e8943161e 100644 --- a/op_crates/web/02_abort_signal.js +++ b/op_crates/web/02_abort_signal.js @@ -64,22 +64,35 @@ } const handlerSymbol = Symbol("eventHandlers"); + + function makeWrappedHandler(handler) { + function wrappedHandler(...args) { + if (typeof wrappedHandler.handler !== "function") { + return; + } + return wrappedHandler.handler.call(this, ...args); + } + wrappedHandler.handler = handler; + return wrappedHandler; + } function defineEventHandler(emitter, name) { // HTML specification section 8.1.5.1 Object.defineProperty(emitter, `on${name}`, { get() { - return this[handlerSymbol]?.get(name); + return this[handlerSymbol]?.get(name)?.handler; }, set(value) { - const oldListener = this[handlerSymbol]?.get(name); - if (oldListener) { - this.removeEventListener(name, oldListener); - } if (!this[handlerSymbol]) { this[handlerSymbol] = new Map(); } - this.addEventListener(name, value); - this[handlerSymbol].set(value); + let handlerWrapper = this[handlerSymbol]?.get(name); + if (handlerWrapper) { + handlerWrapper.handler = value; + } else { + handlerWrapper = makeWrappedHandler(value); + this.addEventListener(name, handlerWrapper); + } + this[handlerSymbol].set(name, handlerWrapper); }, configurable: true, enumerable: true, diff --git a/op_crates/web/abort_controller_test.js b/op_crates/web/abort_controller_test.js index 4d37419860..a65bc69ff8 100644 --- a/op_crates/web/abort_controller_test.js +++ b/op_crates/web/abort_controller_test.js @@ -95,6 +95,23 @@ function abortSignalEventOrder() { assertEquals(arr[1], 2); assertEquals(arr[2], 3); } + +function abortSignalEventOrderComplex() { + const arr = []; + const controller = new AbortController(); + const { signal } = controller; + signal.addEventListener("abort", () => arr.push(1)); + signal.onabort = () => { + throw new Error(); + }; + signal.addEventListener("abort", () => arr.push(3)); + signal.onabort = () => arr.push(2); + controller.abort(); + assertEquals(arr[0], 1); + assertEquals(arr[1], 2); + assertEquals(arr[2], 3); +} + function abortSignalHandlerLocation() { const controller = new AbortController(); const { signal } = controller; @@ -109,6 +126,7 @@ function main() { controllerHasProperToString(); abortSignalIllegalConstructor(); abortSignalEventOrder(); + abortSignalEventOrderComplex(); abortSignalHandlerLocation(); }