mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-23 23:57:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
206
toolkit/components/promiseworker/worker/PromiseWorker.js
Normal file
206
toolkit/components/promiseworker/worker/PromiseWorker.js
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* A wrapper around `self` with extended capabilities designed
|
||||
* to simplify main thread-to-worker thread asynchronous function calls.
|
||||
*
|
||||
* This wrapper:
|
||||
* - groups requests and responses as a method `post` that returns a `Promise`;
|
||||
* - ensures that exceptions thrown on the worker thread are correctly serialized;
|
||||
* - provides some utilities for benchmarking various operations.
|
||||
*
|
||||
* Generally, you should use PromiseWorker.js along with its main thread-side
|
||||
* counterpart PromiseWorker.jsm.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
if (typeof Components != "undefined") {
|
||||
throw new Error("This module is meant to be used from the worker thread");
|
||||
}
|
||||
if (typeof require == "undefined" || typeof module == "undefined") {
|
||||
throw new Error("this module is meant to be imported using the implementation of require() at resource://gre/modules/workers/require.js");
|
||||
}
|
||||
|
||||
importScripts("resource://gre/modules/workers/require.js");
|
||||
|
||||
/**
|
||||
* Built-in JavaScript exceptions that may be serialized without
|
||||
* loss of information.
|
||||
*/
|
||||
const EXCEPTION_NAMES = {
|
||||
EvalError: "EvalError",
|
||||
InternalError: "InternalError",
|
||||
RangeError: "RangeError",
|
||||
ReferenceError: "ReferenceError",
|
||||
SyntaxError: "SyntaxError",
|
||||
TypeError: "TypeError",
|
||||
URIError: "URIError",
|
||||
};
|
||||
|
||||
/**
|
||||
* A constructor used to return data to the caller thread while
|
||||
* also executing some specific treatment (e.g. shutting down
|
||||
* the current thread, transmitting data instead of copying it).
|
||||
*
|
||||
* @param {object=} data The data to return to the caller thread.
|
||||
* @param {object=} meta Additional instructions, as an object
|
||||
* that may contain the following fields:
|
||||
* - {bool} shutdown If |true|, shut down the current thread after
|
||||
* having sent the result.
|
||||
* - {Array} transfers An array of objects that should be transferred
|
||||
* instead of being copied.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function Meta(data, meta) {
|
||||
this.data = data;
|
||||
this.meta = meta;
|
||||
}
|
||||
exports.Meta = Meta;
|
||||
|
||||
/**
|
||||
* Base class for a worker.
|
||||
*
|
||||
* Derived classes are expected to provide the following methods:
|
||||
* {
|
||||
* dispatch: function(method, args) {
|
||||
* // Dispatch a call to method `method` with args `args`
|
||||
* },
|
||||
* log: function(...msg) {
|
||||
* // Log (or discard) messages (optional)
|
||||
* },
|
||||
* postMessage: function(message, ...transfers) {
|
||||
* // Post a message to the main thread
|
||||
* },
|
||||
* close: function() {
|
||||
* // Close the worker
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* By default, the AbstractWorker is not connected to a message port,
|
||||
* hence will not receive anything.
|
||||
*
|
||||
* To connect it, use `onmessage`, as follows:
|
||||
* self.addEventListener("message", msg => myWorkerInstance.handleMessage(msg));
|
||||
*/
|
||||
function AbstractWorker(agent) {
|
||||
this._agent = agent;
|
||||
}
|
||||
AbstractWorker.prototype = {
|
||||
// Default logger: discard all messages
|
||||
log: function() {
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a message.
|
||||
*/
|
||||
handleMessage: function(msg) {
|
||||
let data = msg.data;
|
||||
this.log("Received message", data);
|
||||
let id = data.id;
|
||||
|
||||
let start;
|
||||
let options;
|
||||
if (data.args) {
|
||||
options = data.args[data.args.length - 1];
|
||||
}
|
||||
// If |outExecutionDuration| option was supplied, start measuring the
|
||||
// duration of the operation.
|
||||
if (options && typeof options === "object" && "outExecutionDuration" in options) {
|
||||
start = Date.now();
|
||||
}
|
||||
|
||||
let result;
|
||||
let exn;
|
||||
let durationMs;
|
||||
let method = data.fun;
|
||||
try {
|
||||
this.log("Calling method", method);
|
||||
result = this.dispatch(method, data.args);
|
||||
this.log("Method", method, "succeeded");
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
this.log("Error while calling agent method", method, exn, exn.moduleStack || exn.stack || "");
|
||||
}
|
||||
|
||||
if (start) {
|
||||
// Record duration
|
||||
durationMs = Date.now() - start;
|
||||
this.log("Method took", durationMs, "ms");
|
||||
}
|
||||
|
||||
// Now, post a reply, possibly as an uncaught error.
|
||||
// We post this message from outside the |try ... catch| block
|
||||
// to avoid capturing errors that take place during |postMessage| and
|
||||
// built-in serialization.
|
||||
if (!exn) {
|
||||
this.log("Sending positive reply", result, "id is", id);
|
||||
if (result instanceof Meta) {
|
||||
if ("transfers" in result.meta) {
|
||||
// Take advantage of zero-copy transfers
|
||||
this.postMessage({ok: result.data, id: id, durationMs: durationMs},
|
||||
result.meta.transfers);
|
||||
} else {
|
||||
this.postMessage({ok: result.data, id:id, durationMs: durationMs});
|
||||
}
|
||||
if (result.meta.shutdown || false) {
|
||||
// Time to close the worker
|
||||
this.close();
|
||||
}
|
||||
} else {
|
||||
this.postMessage({ok: result, id:id, durationMs: durationMs});
|
||||
}
|
||||
} else if (exn.constructor.name in EXCEPTION_NAMES) {
|
||||
// Rather than letting the DOM mechanism [de]serialize built-in
|
||||
// JS errors, which loses lots of information (in particular,
|
||||
// the constructor name, the moduleName and the moduleStack),
|
||||
// we [de]serialize them manually with a little more care.
|
||||
this.log("Sending back exception", exn.constructor.name, "id is", id);
|
||||
let error = {
|
||||
exn: exn.constructor.name,
|
||||
message: exn.message,
|
||||
fileName: exn.moduleName || exn.fileName,
|
||||
lineNumber: exn.lineNumber,
|
||||
stack: exn.moduleStack
|
||||
};
|
||||
this.postMessage({fail: error, id: id, durationMs: durationMs});
|
||||
} else if (exn == StopIteration) {
|
||||
// StopIteration is a well-known singleton, and requires a
|
||||
// slightly different treatment.
|
||||
this.log("Sending back StopIteration, id is", id);
|
||||
let error = {
|
||||
exn: "StopIteration"
|
||||
};
|
||||
this.postMessage({fail: error, id: id, durationMs: durationMs});
|
||||
} else if ("toMsg" in exn) {
|
||||
// Extension mechanism for exception [de]serialization. We
|
||||
// assume that any exception with a method `toMsg()` knows how
|
||||
// to serialize itself. The other side is expected to have
|
||||
// registered a deserializer using the `ExceptionHandlers`
|
||||
// object.
|
||||
this.log("Sending back an error that knows how to serialize itself", exn, "id is", id);
|
||||
let msg = exn.toMsg();
|
||||
this.postMessage({fail: msg, id:id, durationMs: durationMs});
|
||||
} else {
|
||||
// If we encounter an exception for which we have no
|
||||
// serialization mechanism in place, we have no choice but to
|
||||
// let the DOM handle said [de]serialization. We can just
|
||||
// attempt to mitigate the data loss by injecting `moduleName` and
|
||||
// `moduleStack`.
|
||||
this.log("Sending back regular error", exn, exn.moduleStack || exn.stack, "id is", id);
|
||||
|
||||
try {
|
||||
// Attempt to introduce human-readable filename and stack
|
||||
exn.filename = exn.moduleName;
|
||||
exn.stack = exn.moduleStack;
|
||||
} catch (_) {
|
||||
// Nothing we can do
|
||||
}
|
||||
throw exn;
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.AbstractWorker = AbstractWorker;
|
||||
Loading…
Add table
Add a link
Reference in a new issue