Skip to content

Commit

Permalink
fix: align DedicatedWorkerGlobalScope event handlers to spec (#11353)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreu Botella authored Jul 10, 2021
1 parent 67c9937 commit eea6000
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 32 deletions.
5 changes: 5 additions & 0 deletions cli/tests/integration/run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
5 changes: 5 additions & 0 deletions cli/tests/worker_event_handler_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const w = new Worker(
new URL("./workers/worker_event_handlers.js", import.meta.url).href,
{ type: "module" },
);
w.postMessage({});
11 changes: 11 additions & 0 deletions cli/tests/worker_event_handler_test.js.out
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions cli/tests/workers/worker_event_handlers.js
Original file line number Diff line number Diff line change
@@ -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();
});
33 changes: 30 additions & 3 deletions runtime/js/01_web_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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);
Expand Down
36 changes: 7 additions & 29 deletions runtime/js/99_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'";
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -585,6 +560,9 @@ delete Object.prototype.__proto__;

eventTarget.setEventTargetData(globalThis);

defineEventHandler(self, "message", null);
defineEventHandler(self, "error", null, true);

runtimeStart(
runtimeOptions,
internalName ?? name,
Expand Down

0 comments on commit eea6000

Please sign in to comment.