[api-minor] Only use Workers when postMessage transfers are supported (PR 11123 follow-up)

Given that all modern browsers now support `postMessage` transfers, and have for years, it no longer seems necessary for the PDF.js library to support using Workers unless the `postMessage` transfers functionality is available.
This patch is a follow-up to PR 11123, which made it impossible to *manually* disable `postMessage` transfers for performance reasons (since it increases memory usage), which hasn't caused any bug reports as far as I know.[1]

Hence we'll now only support *proper* Worker implementations, with fully working `postMessage` transfers, and fallback to using "fake" Workers otherwise.

---
[1] At the time of that PR we still "supported" IE, which is why this code was left intact.
This commit is contained in:
Jonas Jenwald 2021-11-19 13:51:18 +01:00
parent 9f4a2cf5ce
commit 6f22327e61
3 changed files with 9 additions and 41 deletions

View File

@ -75,16 +75,9 @@ class WorkerMessageHandler {
} }
testMessageProcessed = true; testMessageProcessed = true;
// check if Uint8Array can be sent to worker // Ensure that `TypedArray`s can be sent to the worker,
if (!(data instanceof Uint8Array)) { // and that `postMessage` transfers are supported.
handler.send("test", null); handler.send("test", data instanceof Uint8Array && data[0] === 255);
return;
}
// making sure postMessage transfers are working
const supportTransfers = data[0] === 255;
handler.postMessageTransfers = supportTransfers;
handler.send("test", { supportTransfers });
}); });
handler.on("configure", function wphConfigure(data) { handler.on("configure", function wphConfigure(data) {
@ -156,10 +149,6 @@ class WorkerMessageHandler {
const workerHandlerName = docParams.docId + "_worker"; const workerHandlerName = docParams.docId + "_worker";
let handler = new MessageHandler(workerHandlerName, docId, port); let handler = new MessageHandler(workerHandlerName, docId, port);
// Ensure that postMessage transfers are always correctly enabled/disabled,
// to prevent "DataCloneError" in browsers without transfers support.
handler.postMessageTransfers = docParams.postMessageTransfers;
function ensureNotTerminated() { function ensureNotTerminated() {
if (terminated) { if (terminated) {
throw new Error("Worker was terminated"); throw new Error("Worker was terminated");

View File

@ -439,7 +439,6 @@ function getDocument(src) {
workerId, workerId,
worker.port worker.port
); );
messageHandler.postMessageTransfers = worker.postMessageTransfers;
const transport = new WorkerTransport( const transport = new WorkerTransport(
messageHandler, messageHandler,
task, task,
@ -498,7 +497,6 @@ async function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
}, },
maxImageSize: source.maxImageSize, maxImageSize: source.maxImageSize,
disableFontFace: source.disableFontFace, disableFontFace: source.disableFontFace,
postMessageTransfers: worker.postMessageTransfers,
docBaseUrl: source.docBaseUrl, docBaseUrl: source.docBaseUrl,
ignoreErrors: source.ignoreErrors, ignoreErrors: source.ignoreErrors,
isEvalSupported: source.isEvalSupported, isEvalSupported: source.isEvalSupported,
@ -2079,7 +2077,6 @@ class PDFWorker {
this.name = name; this.name = name;
this.destroyed = false; this.destroyed = false;
this.postMessageTransfers = true;
this.verbosity = verbosity; this.verbosity = verbosity;
this._readyCapability = createPromiseCapability(); this._readyCapability = createPromiseCapability();
@ -2188,13 +2185,10 @@ class PDFWorker {
return; // worker was destroyed return; // worker was destroyed
} }
if (data) { if (data) {
// supportTypedArray
this._messageHandler = messageHandler; this._messageHandler = messageHandler;
this._port = worker; this._port = worker;
this._webWorker = worker; this._webWorker = worker;
if (!data.supportTransfers) {
this.postMessageTransfers = false;
}
this._readyCapability.resolve(); this._readyCapability.resolve();
// Send global setting, e.g. verbosity level. // Send global setting, e.g. verbosity level.
messageHandler.send("configure", { messageHandler.send("configure", {
@ -2222,7 +2216,7 @@ class PDFWorker {
}); });
const sendTest = () => { const sendTest = () => {
const testObj = new Uint8Array([this.postMessageTransfers ? 255 : 0]); const testObj = new Uint8Array([255]);
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
// typed array. Also, checking if we can use transfers. // typed array. Also, checking if we can use transfers.
try { try {

View File

@ -83,7 +83,6 @@ class MessageHandler {
this.comObj = comObj; this.comObj = comObj;
this.callbackId = 1; this.callbackId = 1;
this.streamId = 1; this.streamId = 1;
this.postMessageTransfers = true;
this.streamSinks = Object.create(null); this.streamSinks = Object.create(null);
this.streamControllers = Object.create(null); this.streamControllers = Object.create(null);
this.callbackCapabilities = Object.create(null); this.callbackCapabilities = Object.create(null);
@ -180,7 +179,7 @@ class MessageHandler {
* @param {Array} [transfers] - List of transfers/ArrayBuffers. * @param {Array} [transfers] - List of transfers/ArrayBuffers.
*/ */
send(actionName, data, transfers) { send(actionName, data, transfers) {
this._postMessage( this.comObj.postMessage(
{ {
sourceName: this.sourceName, sourceName: this.sourceName,
targetName: this.targetName, targetName: this.targetName,
@ -204,7 +203,7 @@ class MessageHandler {
const capability = createPromiseCapability(); const capability = createPromiseCapability();
this.callbackCapabilities[callbackId] = capability; this.callbackCapabilities[callbackId] = capability;
try { try {
this._postMessage( this.comObj.postMessage(
{ {
sourceName: this.sourceName, sourceName: this.sourceName,
targetName: this.targetName, targetName: this.targetName,
@ -247,7 +246,7 @@ class MessageHandler {
cancelCall: null, cancelCall: null,
isClosed: false, isClosed: false,
}; };
this._postMessage( comObj.postMessage(
{ {
sourceName, sourceName,
targetName, targetName,
@ -322,7 +321,7 @@ class MessageHandler {
this.sinkCapability = createPromiseCapability(); this.sinkCapability = createPromiseCapability();
this.ready = this.sinkCapability.promise; this.ready = this.sinkCapability.promise;
} }
self._postMessage( comObj.postMessage(
{ {
sourceName, sourceName,
targetName, targetName,
@ -549,20 +548,6 @@ class MessageHandler {
delete this.streamControllers[streamId]; delete this.streamControllers[streamId];
} }
/**
* Sends raw message to the comObj.
* @param {Object} message - Raw message.
* @param transfers List of transfers/ArrayBuffers, or undefined.
* @private
*/
_postMessage(message, transfers) {
if (transfers && this.postMessageTransfers) {
this.comObj.postMessage(message, transfers);
} else {
this.comObj.postMessage(message);
}
}
destroy() { destroy() {
this.comObj.removeEventListener("message", this._onComObjOnMessage); this.comObj.removeEventListener("message", this._onComObjOnMessage);
} }