diff options
Diffstat (limited to 'devtools/shared/worker')
-rw-r--r-- | devtools/shared/worker/moz.build | 2 | ||||
-rw-r--r-- | devtools/shared/worker/tests/browser/browser_worker-01.js | 22 | ||||
-rw-r--r-- | devtools/shared/worker/tests/browser/browser_worker-02.js | 6 | ||||
-rw-r--r-- | devtools/shared/worker/tests/browser/browser_worker-03.js | 4 | ||||
-rw-r--r-- | devtools/shared/worker/worker.js | 174 | ||||
-rw-r--r-- | devtools/shared/worker/worker.sys.mjs | 157 |
6 files changed, 171 insertions, 194 deletions
diff --git a/devtools/shared/worker/moz.build b/devtools/shared/worker/moz.build index 79a71ca5ce..87dfbbedf7 100644 --- a/devtools/shared/worker/moz.build +++ b/devtools/shared/worker/moz.build @@ -9,5 +9,5 @@ if CONFIG["MOZ_BUILD_APP"] != "mobile/android": DevToolsModules( "helper.js", - "worker.js", + "worker.sys.mjs", ) diff --git a/devtools/shared/worker/tests/browser/browser_worker-01.js b/devtools/shared/worker/tests/browser/browser_worker-01.js index a8dafcf4cb..f8323e218e 100644 --- a/devtools/shared/worker/tests/browser/browser_worker-01.js +++ b/devtools/shared/worker/tests/browser/browser_worker-01.js @@ -3,8 +3,9 @@ "use strict"; -// Tests that the devtools/shared/worker communicates properly -// as both CommonJS module and as a JSM. +const { DevToolsWorker, workerify } = ChromeUtils.importESModule( + "resource://devtools/shared/worker/worker.sys.mjs" +); const BUFFER_SIZE = 8; @@ -15,22 +16,16 @@ registerCleanupFunction(function () { add_task(async function () { // Test both CJS and JSM versions - await testWorker("JSM", () => - ChromeUtils.import("resource://devtools/shared/worker/worker.js") - ); - await testWorker("CommonJS", () => - require("resource://devtools/shared/worker/worker.js") - ); + await testWorker(); await testTransfer(); }); -async function testWorker(context, workerFactory) { +async function testWorker() { // Needed for blob:null Services.prefs.setBoolPref( "security.allow_parent_unrestricted_js_loads", true ); - const { DevToolsWorker, workerify } = workerFactory(); const blob = new Blob( [ @@ -71,13 +66,13 @@ createTask(self, "groupByField", function({ is( Object.keys(results.groups).join(","), "France,Nigeria", - `worker should have returned the expected result in ${context}` + `worker should have returned the expected result` ); URL.revokeObjectURL(WORKER_URL); const fn = workerify(x => x * x); - is(await fn(5), 25, `workerify works in ${context}`); + is(await fn(5), 25, `workerify works`); fn.destroy(); worker.destroy(); @@ -88,9 +83,6 @@ async function testTransfer() { "security.allow_parent_unrestricted_js_loads", true ); - const { workerify } = ChromeUtils.import( - "resource://devtools/shared/worker/worker.js" - ); const workerFn = workerify(({ buf }) => buf.byteLength); const buf = new ArrayBuffer(BUFFER_SIZE); diff --git a/devtools/shared/worker/tests/browser/browser_worker-02.js b/devtools/shared/worker/tests/browser/browser_worker-02.js index 80c50cf887..c051946aee 100644 --- a/devtools/shared/worker/tests/browser/browser_worker-02.js +++ b/devtools/shared/worker/tests/browser/browser_worker-02.js @@ -5,9 +5,9 @@ // Tests errors are handled properly by the DevToolsWorker. -const { - DevToolsWorker, -} = require("resource://devtools/shared/worker/worker.js"); +const { DevToolsWorker } = ChromeUtils.importESModule( + "resource://devtools/shared/worker/worker.sys.mjs" +); const blob = new Blob( [ diff --git a/devtools/shared/worker/tests/browser/browser_worker-03.js b/devtools/shared/worker/tests/browser/browser_worker-03.js index 34e7688e73..9a7659979e 100644 --- a/devtools/shared/worker/tests/browser/browser_worker-03.js +++ b/devtools/shared/worker/tests/browser/browser_worker-03.js @@ -8,7 +8,9 @@ // // And tests `workerify` by doing so. -const { workerify } = require("resource://devtools/shared/worker/worker.js"); +const { workerify } = ChromeUtils.importESModule( + "resource://devtools/shared/worker/worker.sys.mjs" +); function square(x) { return x * x; } diff --git a/devtools/shared/worker/worker.js b/devtools/shared/worker/worker.js deleted file mode 100644 index f9e5c7f4f0..0000000000 --- a/devtools/shared/worker/worker.js +++ /dev/null @@ -1,174 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* global ChromeWorker */ - -(function (factory) { - if (this.module && module.id.includes("worker")) { - // require - const dumpn = require("devtools/shared/DevToolsUtils").dumpn; - factory.call(this, require, exports, module, ChromeWorker, dumpn); - } else { - // Cu.import - const { require } = ChromeUtils.importESModule( - "resource://devtools/shared/loader/Loader.sys.mjs" - ); - this.isWorker = false; - this.console = console; - factory.call(this, require, this, { exports: this }, ChromeWorker, null); - this.EXPORTED_SYMBOLS = ["DevToolsWorker", "workerify"]; - } -}).call(this, function (require, exports, module, ChromeWorker, dumpn) { - let MESSAGE_COUNTER = 0; - - /** - * Creates a wrapper around a ChromeWorker, providing easy - * communication to offload demanding tasks. The corresponding URL - * must implement the interface provided by `devtools/shared/worker/helper`. - * - * @param {string} url - * The URL of the worker. - * @param Object opts - * An option with the following optional fields: - * - name: a name that will be printed with logs - * - verbose: log incoming and outgoing messages - */ - function DevToolsWorker(url, opts) { - opts = opts || {}; - this._worker = new ChromeWorker(url); - this._verbose = opts.verbose; - this._name = opts.name; - - this._worker.addEventListener("error", this.onError); - } - exports.DevToolsWorker = DevToolsWorker; - - /** - * Performs the given task in a chrome worker, passing in data. - * Returns a promise that resolves when the task is completed, resulting in - * the return value of the task. - * - * @param {string} task - * The name of the task to execute in the worker. - * @param {any} data - * Data to be passed into the task implemented by the worker. - * @param {undefined|Array} transfer - * Optional array of transferable objects to transfer ownership of. - * @return {Promise} - */ - DevToolsWorker.prototype.performTask = function (task, data, transfer) { - if (this._destroyed) { - return Promise.reject( - "Cannot call performTask on a destroyed DevToolsWorker" - ); - } - const worker = this._worker; - const id = ++MESSAGE_COUNTER; - const payload = { task, id, data }; - - if (this._verbose && dumpn) { - dumpn( - "Sending message to worker" + - (this._name ? " (" + this._name + ")" : "") + - ": " + - JSON.stringify(payload, null, 2) - ); - } - worker.postMessage(payload, transfer); - - return new Promise((resolve, reject) => { - const listener = ({ data: result }) => { - if (this._verbose && dumpn) { - dumpn( - "Received message from worker" + - (this._name ? " (" + this._name + ")" : "") + - ": " + - JSON.stringify(result, null, 2) - ); - } - - if (result.id !== id) { - return; - } - worker.removeEventListener("message", listener); - if (result.error) { - reject(result.error); - } else { - resolve(result.response); - } - }; - - worker.addEventListener("message", listener); - }); - }; - - /** - * Terminates the underlying worker. Use when no longer needing the worker. - */ - DevToolsWorker.prototype.destroy = function () { - this._worker.terminate(); - this._worker = null; - this._destroyed = true; - }; - - DevToolsWorker.prototype.onError = function ({ message, filename, lineno }) { - dump(new Error(message + " @ " + filename + ":" + lineno) + "\n"); - }; - - /** - * Takes a function and returns a Worker-wrapped version of the same function. - * Returns a promise upon resolution. - * @see `./devtools/shared/shared/tests/browser/browser_devtools-worker-03.js - * - * ⚠ This should only be used for tests or A/B testing performance ⚠ - * - * The original function must: - * - * Be a pure function, that is, not use any variables not declared within the - * function, or its arguments. - * - * Return a value or a promise. - * - * Note any state change in the worker will not affect the callee's context. - * - * @param {function} fn - * @return {function} - */ - function workerify(fn) { - console.warn( - "`workerify` should only be used in tests or measuring performance. " + - "This creates an object URL on the browser window, and should not be " + - "used in production." - ); - // Fetch modules here as we don't want to include it normally. - const { URL, Blob } = Services.wm.getMostRecentWindow("navigator:browser"); - const stringifiedFn = createWorkerString(fn); - const blob = new Blob([stringifiedFn]); - const url = URL.createObjectURL(blob); - const worker = new DevToolsWorker(url); - - const wrapperFn = (data, transfer) => - worker.performTask("workerifiedTask", data, transfer); - - wrapperFn.destroy = function () { - URL.revokeObjectURL(url); - worker.destroy(); - }; - - return wrapperFn; - } - exports.workerify = workerify; - - /** - * Takes a function, and stringifies it, attaching the worker-helper.js - * boilerplate hooks. - */ - function createWorkerString(fn) { - return `importScripts("resource://gre/modules/workers/require.js"); - const { createTask } = require("resource://devtools/shared/worker/helper.js"); - createTask(self, "workerifiedTask", ${fn.toString()});`; - } -}); diff --git a/devtools/shared/worker/worker.sys.mjs b/devtools/shared/worker/worker.sys.mjs new file mode 100644 index 0000000000..4b8840dde2 --- /dev/null +++ b/devtools/shared/worker/worker.sys.mjs @@ -0,0 +1,157 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* global ChromeWorker */ + +let MESSAGE_COUNTER = 0; + +function dumpn(_msg) { + // dump(msg + "\n"); +} + +/** + * Creates a wrapper around a ChromeWorker, providing easy + * communication to offload demanding tasks. The corresponding URL + * must implement the interface provided by `devtools/shared/worker/helper`. + * + * @param {string} url + * The URL of the worker. + * @param Object opts + * An option with the following optional fields: + * - name: a name that will be printed with logs + * - verbose: log incoming and outgoing messages + */ +export function DevToolsWorker(url, opts) { + opts = opts || {}; + this._worker = new ChromeWorker(url); + this._verbose = opts.verbose; + this._name = opts.name; + + this._worker.addEventListener("error", this.onError); +} + +/** + * Performs the given task in a chrome worker, passing in data. + * Returns a promise that resolves when the task is completed, resulting in + * the return value of the task. + * + * @param {string} task + * The name of the task to execute in the worker. + * @param {any} data + * Data to be passed into the task implemented by the worker. + * @param {undefined|Array} transfer + * Optional array of transferable objects to transfer ownership of. + * @return {Promise} + */ +DevToolsWorker.prototype.performTask = function (task, data, transfer) { + if (this._destroyed) { + return Promise.reject( + "Cannot call performTask on a destroyed DevToolsWorker" + ); + } + const worker = this._worker; + const id = ++MESSAGE_COUNTER; + const payload = { task, id, data }; + + if (this._verbose && dumpn) { + dumpn( + "Sending message to worker" + + (this._name ? " (" + this._name + ")" : "") + + ": " + + JSON.stringify(payload, null, 2) + ); + } + worker.postMessage(payload, transfer); + + return new Promise((resolve, reject) => { + const listener = ({ data: result }) => { + if (this._verbose && dumpn) { + dumpn( + "Received message from worker" + + (this._name ? " (" + this._name + ")" : "") + + ": " + + JSON.stringify(result, null, 2) + ); + } + + if (result.id !== id) { + return; + } + worker.removeEventListener("message", listener); + if (result.error) { + reject(result.error); + } else { + resolve(result.response); + } + }; + + worker.addEventListener("message", listener); + }); +}; + +/** + * Terminates the underlying worker. Use when no longer needing the worker. + */ +DevToolsWorker.prototype.destroy = function () { + this._worker.terminate(); + this._worker = null; + this._destroyed = true; +}; + +DevToolsWorker.prototype.onError = function ({ message, filename, lineno }) { + dump(new Error(message + " @ " + filename + ":" + lineno) + "\n"); +}; + +/** + * Takes a function and returns a Worker-wrapped version of the same function. + * Returns a promise upon resolution. + * @see `./devtools/shared/shared/tests/browser/browser_devtools-worker-03.js + * + * ⚠ This should only be used for tests or A/B testing performance ⚠ + * + * The original function must: + * + * Be a pure function, that is, not use any variables not declared within the + * function, or its arguments. + * + * Return a value or a promise. + * + * Note any state change in the worker will not affect the callee's context. + * + * @param {function} fn + * @return {function} + */ +export function workerify(fn) { + console.warn( + "`workerify` should only be used in tests or measuring performance. " + + "This creates an object URL on the browser window, and should not be " + + "used in production." + ); + // Fetch modules here as we don't want to include it normally. + const { URL, Blob } = Services.wm.getMostRecentWindow("navigator:browser"); + const stringifiedFn = createWorkerString(fn); + const blob = new Blob([stringifiedFn]); + const url = URL.createObjectURL(blob); + const worker = new DevToolsWorker(url); + + const wrapperFn = (data, transfer) => + worker.performTask("workerifiedTask", data, transfer); + + wrapperFn.destroy = function () { + URL.revokeObjectURL(url); + worker.destroy(); + }; + + return wrapperFn; +} + +/** + * Takes a function, and stringifies it, attaching the worker-helper.js + * boilerplate hooks. + */ +function createWorkerString(fn) { + return `importScripts("resource://gre/modules/workers/require.js"); + const { createTask } = require("resource://devtools/shared/worker/helper.js"); + createTask(self, "workerifiedTask", ${fn.toString()});`; +} |