summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreu Botella <abb@randomunok.com>2021-07-10 23:32:10 +0200
committerGitHub <noreply@github.com>2021-07-10 23:32:10 +0200
commiteea6000ef6e30e6684995619e630d3beb7d7484b (patch)
tree8f61e5bcaca9afacf4b3471cbe3c2ef979cb5b39
parent67c9937e6658c2be9b54cd95132a1055756e433b (diff)
fix: align DedicatedWorkerGlobalScope event handlers to spec (#11353)
-rw-r--r--cli/tests/integration/run_tests.rs5
-rw-r--r--cli/tests/worker_event_handler_test.js5
-rw-r--r--cli/tests/worker_event_handler_test.js.out11
-rw-r--r--cli/tests/workers/worker_event_handlers.js23
-rw-r--r--runtime/js/01_web_util.js33
-rw-r--r--runtime/js/99_main.js36
6 files changed, 81 insertions, 32 deletions
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs
index d2997d747..2e2b0400c 100644
--- a/cli/tests/integration/run_tests.rs
+++ b/cli/tests/integration/run_tests.rs
@@ -1155,6 +1155,11 @@ itest!(error_import_map_unable_to_load {
exit_code: 1,
});
+itest!(worker_event_handler_test {
+ args: "run --quiet --reload --allow-read worker_event_handler_test.js",
+ output: "worker_event_handler_test.js.out",
+});
+
#[test]
fn no_validate_asm() {
let output = util::deno_cmd()
diff --git a/cli/tests/worker_event_handler_test.js b/cli/tests/worker_event_handler_test.js
new file mode 100644
index 000000000..e0ce3d9f8
--- /dev/null
+++ b/cli/tests/worker_event_handler_test.js
@@ -0,0 +1,5 @@
+const w = new Worker(
+ new URL("./workers/worker_event_handlers.js", import.meta.url).href,
+ { type: "module" },
+);
+w.postMessage({});
diff --git a/cli/tests/worker_event_handler_test.js.out b/cli/tests/worker_event_handler_test.js.out
new file mode 100644
index 000000000..5556633b1
--- /dev/null
+++ b/cli/tests/worker_event_handler_test.js.out
@@ -0,0 +1,11 @@
+Target from self.onmessage: [object DedicatedWorkerGlobalScope]
+Target from message event listener: [object DedicatedWorkerGlobalScope]
+Arguments from self.onerror: [
+ "Some error message",
+ "",
+ 0,
+ 0,
+ Error: Some error message
+ at [WILDCARD]
+]
+Is event canceled?: true
diff --git a/cli/tests/workers/worker_event_handlers.js b/cli/tests/workers/worker_event_handlers.js
new file mode 100644
index 000000000..c8976f79e
--- /dev/null
+++ b/cli/tests/workers/worker_event_handlers.js
@@ -0,0 +1,23 @@
+self.onmessage = (evt) => {
+ console.log("Target from self.onmessage:", String(evt.target));
+};
+
+self.addEventListener("message", (evt) => {
+ console.log("Target from message event listener:", String(evt.target));
+
+ // Throw an error here so the global's error event will fire.
+ throw new Error("Some error message");
+});
+
+self.onerror = (...args) => {
+ console.log("Arguments from self.onerror:", args);
+ return true;
+};
+
+self.addEventListener("error", (evt) => {
+ // Returning true from self.onerror means that subsequent event listeners
+ // should see the event as canceled.
+ console.log("Is event canceled?:", evt.defaultPrevented);
+
+ self.close();
+});
diff --git a/runtime/js/01_web_util.js b/runtime/js/01_web_util.js
index 4a9825fa1..9b51021f9 100644
--- a/runtime/js/01_web_util.js
+++ b/runtime/js/01_web_util.js
@@ -27,17 +27,41 @@
}
const handlerSymbol = Symbol("eventHandlers");
- function makeWrappedHandler(handler) {
+ function makeWrappedHandler(handler, isSpecialErrorEventHandler) {
function wrappedHandler(...args) {
if (typeof wrappedHandler.handler !== "function") {
return;
}
+ if (isSpecialErrorEventHandler) {
+ const evt = args[0];
+ if (evt instanceof ErrorEvent && evt.type === "error") {
+ const ret = FunctionPrototypeCall(
+ wrappedHandler.handler,
+ this,
+ evt.message,
+ evt.filename,
+ evt.lineno,
+ evt.colno,
+ evt.error,
+ );
+ if (ret === true) {
+ evt.preventDefault();
+ }
+ return;
+ }
+ }
+
return FunctionPrototypeCall(wrappedHandler.handler, this, ...args);
}
wrappedHandler.handler = handler;
return wrappedHandler;
}
- function defineEventHandler(emitter, name, defaultValue = undefined) {
+ function defineEventHandler(
+ emitter,
+ name,
+ defaultValue = undefined,
+ isSpecialErrorEventHandler = false,
+ ) {
// HTML specification section 8.1.5.1
ObjectDefineProperty(emitter, `on${name}`, {
get() {
@@ -56,7 +80,10 @@
if (handlerWrapper) {
handlerWrapper.handler = value;
} else {
- handlerWrapper = makeWrappedHandler(value);
+ handlerWrapper = makeWrappedHandler(
+ value,
+ isSpecialErrorEventHandler,
+ );
this.addEventListener(name, handlerWrapper);
}
MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index b473acdef..71480e5a0 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -88,11 +88,6 @@ delete Object.prototype.__proto__;
core.opSync("op_worker_close");
}
- // TODO(bartlomieju): remove these functions
- // Stuff for workers
- const onmessage = () => {};
- const onerror = () => {};
-
function postMessage(message, transferOrOptions = {}) {
const prefix =
"Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope'";
@@ -144,39 +139,19 @@ delete Object.prototype.__proto__;
});
try {
- if (globalThis.onmessage) {
- await globalThis.onmessage(msgEvent);
- }
globalDispatchEvent(msgEvent);
} catch (e) {
- let handled = false;
-
const errorEvent = new ErrorEvent("error", {
cancelable: true,
message: e.message,
lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
colno: e.columnNumber ? e.columnNumber + 1 : undefined,
filename: e.fileName,
- error: null,
+ error: e,
});
- if (globalThis["onerror"]) {
- const ret = globalThis.onerror(
- e.message,
- e.fileName,
- e.lineNumber,
- e.columnNumber,
- e,
- );
- handled = ret === true;
- }
-
globalDispatchEvent(errorEvent);
- if (errorEvent.defaultPrevented) {
- handled = true;
- }
-
- if (!handled) {
+ if (!errorEvent.defaultPrevented) {
core.opSync(
"op_worker_unhandled_error",
e.message,
@@ -465,8 +440,8 @@ delete Object.prototype.__proto__;
get: () => workerNavigator,
},
self: util.readOnly(globalThis),
- onmessage: util.writable(onmessage),
- onerror: util.writable(onerror),
+ onmessage: util.writable(null),
+ onerror: util.writable(null),
// TODO(bartlomieju): should be readonly?
close: util.nonEnumerable(workerClose),
postMessage: util.writable(postMessage),
@@ -585,6 +560,9 @@ delete Object.prototype.__proto__;
eventTarget.setEventTargetData(globalThis);
+ defineEventHandler(self, "message", null);
+ defineEventHandler(self, "error", null, true);
+
runtimeStart(
runtimeOptions,
internalName ?? name,