summaryrefslogtreecommitdiff
path: root/runtime/js/11_workers.js
diff options
context:
space:
mode:
authorTim Ramlot <42113979+inteon@users.noreply.github.com>2021-05-11 21:09:09 +0200
committerGitHub <noreply@github.com>2021-05-11 21:09:09 +0200
commit635253bd3a3895f49e6c9606beb852da22fee205 (patch)
treecec9d75354b4e985a376f888564ecb63c99f2643 /runtime/js/11_workers.js
parent0d319161bc19a520df653bc0c8386f14a68efbdb (diff)
feat(runtime/worker): Structured cloning worker message passing (#9323)
This commit upgrade "Worker.postMessage()" implementation to use structured clone algorithm instead of non-spec compliant JSON serialization.
Diffstat (limited to 'runtime/js/11_workers.js')
-rw-r--r--runtime/js/11_workers.js102
1 files changed, 31 insertions, 71 deletions
diff --git a/runtime/js/11_workers.js b/runtime/js/11_workers.js
index 508dd46d4..dca83c818 100644
--- a/runtime/js/11_workers.js
+++ b/runtime/js/11_workers.js
@@ -39,26 +39,8 @@
return core.opAsync("op_host_get_message", id);
}
- const encoder = new TextEncoder();
const decoder = new TextDecoder();
- function encodeMessage(data) {
- const dataJson = JSON.stringify(data);
- return encoder.encode(dataJson);
- }
-
- function decodeMessage(dataIntArray) {
- // Temporary solution until structured clone arrives in v8.
- // Current clone is made by parsing json to byte array and from byte array back to json.
- // In that case "undefined" transforms to empty byte array, but empty byte array does not transform back to undefined.
- // Thats why this special is statement is needed.
- if (dataIntArray.length == 0) {
- return undefined;
- }
- const dataJson = decoder.decode(dataIntArray);
- return JSON.parse(dataJson);
- }
-
/**
* @param {string} permission
* @return {boolean}
@@ -211,18 +193,7 @@
this.#poll();
}
- #handleMessage = (msgData) => {
- let data;
- try {
- data = decodeMessage(new Uint8Array(msgData));
- } catch (e) {
- const msgErrorEvent = new MessageEvent("messageerror", {
- cancelable: false,
- data,
- });
- return;
- }
-
+ #handleMessage = (data) => {
const msgEvent = new MessageEvent("message", {
cancelable: false,
data,
@@ -253,56 +224,44 @@
#poll = async () => {
while (!this.#terminated) {
- const event = await hostGetMessage(this.#id);
+ const [type, data] = await hostGetMessage(this.#id);
// If terminate was called then we ignore all messages
if (this.#terminated) {
return;
}
- const type = event.type;
-
- if (type === "terminalError") {
- this.#terminated = true;
- if (!this.#handleError(event.error)) {
- if (globalThis instanceof Window) {
- throw new Error("Unhandled error event reached main worker.");
- } else {
- core.opSync(
- "op_host_unhandled_error",
- event.error.message,
- );
- }
+ switch (type) {
+ case 0: { // Message
+ const msg = core.deserialize(data);
+ this.#handleMessage(msg);
+ break;
}
- continue;
- }
-
- if (type === "msg") {
- this.#handleMessage(event.data);
- continue;
- }
-
- if (type === "error") {
- if (!this.#handleError(event.error)) {
- if (globalThis instanceof Window) {
- throw new Error("Unhandled error event reached main worker.");
- } else {
- core.opSync(
- "op_host_unhandled_error",
- event.error.message,
- );
+ case 1: { // TerminalError
+ this.#terminated = true;
+ } /* falls through */
+ case 2: { // Error
+ if (!this.#handleError(data)) {
+ if (globalThis instanceof Window) {
+ throw new Error("Unhandled error event reached main worker.");
+ } else {
+ core.opSync(
+ "op_worker_unhandled_error",
+ data.message,
+ );
+ }
}
+ break;
+ }
+ case 3: { // Close
+ log(`Host got "close" message from worker: ${this.#name}`);
+ this.#terminated = true;
+ return;
+ }
+ default: {
+ throw new Error(`Unknown worker event: "${type}"`);
}
- continue;
- }
-
- if (type === "close") {
- log(`Host got "close" message from worker: ${this.#name}`);
- this.#terminated = true;
- return;
}
-
- throw new Error(`Unknown worker event: "${type}"`);
}
};
@@ -317,7 +276,8 @@
return;
}
- hostPostMessage(this.#id, encodeMessage(message));
+ const bufferMsg = core.serialize(message);
+ hostPostMessage(this.#id, bufferMsg);
}
terminate() {