mirror of
https://github.com/denoland/deno.git
synced 2025-01-03 04:48:52 -05:00
fix: align DedicatedWorkerGlobalScope event handlers to spec (#11353)
This commit is contained in:
parent
67c9937e66
commit
eea6000ef6
6 changed files with 81 additions and 32 deletions
|
@ -1155,6 +1155,11 @@ itest!(error_import_map_unable_to_load {
|
||||||
exit_code: 1,
|
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]
|
#[test]
|
||||||
fn no_validate_asm() {
|
fn no_validate_asm() {
|
||||||
let output = util::deno_cmd()
|
let output = util::deno_cmd()
|
||||||
|
|
5
cli/tests/worker_event_handler_test.js
Normal file
5
cli/tests/worker_event_handler_test.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const w = new Worker(
|
||||||
|
new URL("./workers/worker_event_handlers.js", import.meta.url).href,
|
||||||
|
{ type: "module" },
|
||||||
|
);
|
||||||
|
w.postMessage({});
|
11
cli/tests/worker_event_handler_test.js.out
Normal file
11
cli/tests/worker_event_handler_test.js.out
Normal file
|
@ -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
cli/tests/workers/worker_event_handlers.js
Normal file
23
cli/tests/workers/worker_event_handlers.js
Normal file
|
@ -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();
|
||||||
|
});
|
|
@ -27,17 +27,41 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlerSymbol = Symbol("eventHandlers");
|
const handlerSymbol = Symbol("eventHandlers");
|
||||||
function makeWrappedHandler(handler) {
|
function makeWrappedHandler(handler, isSpecialErrorEventHandler) {
|
||||||
function wrappedHandler(...args) {
|
function wrappedHandler(...args) {
|
||||||
if (typeof wrappedHandler.handler !== "function") {
|
if (typeof wrappedHandler.handler !== "function") {
|
||||||
return;
|
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);
|
return FunctionPrototypeCall(wrappedHandler.handler, this, ...args);
|
||||||
}
|
}
|
||||||
wrappedHandler.handler = handler;
|
wrappedHandler.handler = handler;
|
||||||
return wrappedHandler;
|
return wrappedHandler;
|
||||||
}
|
}
|
||||||
function defineEventHandler(emitter, name, defaultValue = undefined) {
|
function defineEventHandler(
|
||||||
|
emitter,
|
||||||
|
name,
|
||||||
|
defaultValue = undefined,
|
||||||
|
isSpecialErrorEventHandler = false,
|
||||||
|
) {
|
||||||
// HTML specification section 8.1.5.1
|
// HTML specification section 8.1.5.1
|
||||||
ObjectDefineProperty(emitter, `on${name}`, {
|
ObjectDefineProperty(emitter, `on${name}`, {
|
||||||
get() {
|
get() {
|
||||||
|
@ -56,7 +80,10 @@
|
||||||
if (handlerWrapper) {
|
if (handlerWrapper) {
|
||||||
handlerWrapper.handler = value;
|
handlerWrapper.handler = value;
|
||||||
} else {
|
} else {
|
||||||
handlerWrapper = makeWrappedHandler(value);
|
handlerWrapper = makeWrappedHandler(
|
||||||
|
value,
|
||||||
|
isSpecialErrorEventHandler,
|
||||||
|
);
|
||||||
this.addEventListener(name, handlerWrapper);
|
this.addEventListener(name, handlerWrapper);
|
||||||
}
|
}
|
||||||
MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
|
MapPrototypeSet(this[handlerSymbol], name, handlerWrapper);
|
||||||
|
|
|
@ -88,11 +88,6 @@ delete Object.prototype.__proto__;
|
||||||
core.opSync("op_worker_close");
|
core.opSync("op_worker_close");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bartlomieju): remove these functions
|
|
||||||
// Stuff for workers
|
|
||||||
const onmessage = () => {};
|
|
||||||
const onerror = () => {};
|
|
||||||
|
|
||||||
function postMessage(message, transferOrOptions = {}) {
|
function postMessage(message, transferOrOptions = {}) {
|
||||||
const prefix =
|
const prefix =
|
||||||
"Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope'";
|
"Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope'";
|
||||||
|
@ -144,39 +139,19 @@ delete Object.prototype.__proto__;
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (globalThis.onmessage) {
|
|
||||||
await globalThis.onmessage(msgEvent);
|
|
||||||
}
|
|
||||||
globalDispatchEvent(msgEvent);
|
globalDispatchEvent(msgEvent);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
let handled = false;
|
|
||||||
|
|
||||||
const errorEvent = new ErrorEvent("error", {
|
const errorEvent = new ErrorEvent("error", {
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
message: e.message,
|
message: e.message,
|
||||||
lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
|
lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
|
||||||
colno: e.columnNumber ? e.columnNumber + 1 : undefined,
|
colno: e.columnNumber ? e.columnNumber + 1 : undefined,
|
||||||
filename: e.fileName,
|
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);
|
globalDispatchEvent(errorEvent);
|
||||||
if (errorEvent.defaultPrevented) {
|
if (!errorEvent.defaultPrevented) {
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handled) {
|
|
||||||
core.opSync(
|
core.opSync(
|
||||||
"op_worker_unhandled_error",
|
"op_worker_unhandled_error",
|
||||||
e.message,
|
e.message,
|
||||||
|
@ -465,8 +440,8 @@ delete Object.prototype.__proto__;
|
||||||
get: () => workerNavigator,
|
get: () => workerNavigator,
|
||||||
},
|
},
|
||||||
self: util.readOnly(globalThis),
|
self: util.readOnly(globalThis),
|
||||||
onmessage: util.writable(onmessage),
|
onmessage: util.writable(null),
|
||||||
onerror: util.writable(onerror),
|
onerror: util.writable(null),
|
||||||
// TODO(bartlomieju): should be readonly?
|
// TODO(bartlomieju): should be readonly?
|
||||||
close: util.nonEnumerable(workerClose),
|
close: util.nonEnumerable(workerClose),
|
||||||
postMessage: util.writable(postMessage),
|
postMessage: util.writable(postMessage),
|
||||||
|
@ -585,6 +560,9 @@ delete Object.prototype.__proto__;
|
||||||
|
|
||||||
eventTarget.setEventTargetData(globalThis);
|
eventTarget.setEventTargetData(globalThis);
|
||||||
|
|
||||||
|
defineEventHandler(self, "message", null);
|
||||||
|
defineEventHandler(self, "error", null, true);
|
||||||
|
|
||||||
runtimeStart(
|
runtimeStart(
|
||||||
runtimeOptions,
|
runtimeOptions,
|
||||||
internalName ?? name,
|
internalName ?? name,
|
||||||
|
|
Loading…
Reference in a new issue