Merge pull request #20662 from Snuffleupagus/getPdfManager-async-read

Convert the data reading in `getPdfManager` to be asynchronous
This commit is contained in:
Tim van der Meij 2026-03-07 13:16:22 +01:00 committed by GitHub
commit d34a15e03f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -222,13 +222,13 @@ class WorkerMessageHandler {
const pdfStream = new PDFWorkerStream({ msgHandler: handler }), const pdfStream = new PDFWorkerStream({ msgHandler: handler }),
fullReader = pdfStream.getFullReader(); fullReader = pdfStream.getFullReader();
const pdfManagerCapability = Promise.withResolvers(); const { promise, resolve, reject } = Promise.withResolvers();
let newPdfManager, let newPdfManager,
cachedChunks = [], cachedChunks = [];
loaded = 0; cancelXHRs = reason => pdfStream.cancelAllRequests(reason);
fullReader.headersReady fullReader.headersReady
.then(function () { .then(() => {
if (!fullReader.isRangeSupported) { if (!fullReader.isRangeSupported) {
return; return;
} }
@ -239,45 +239,35 @@ class WorkerMessageHandler {
newPdfManager = new NetworkPdfManager(pdfManagerArgs); newPdfManager = new NetworkPdfManager(pdfManagerArgs);
// There may be a chance that `newPdfManager` is not initialized for // There may be a chance that `newPdfManager` is not initialized for
// the first few runs of `readchunk` block of code. Be sure to send // the first few iterations of the `readData` code. Be sure to send
// all cached chunks, if any, to chunked_stream via pdf_manager. // all cached chunks, if any, to chunked_stream via pdf_manager.
for (const chunk of cachedChunks) { for (const chunk of cachedChunks) {
newPdfManager.sendProgressiveData(chunk); newPdfManager.sendProgressiveData(chunk);
} }
cachedChunks = null;
cachedChunks = []; resolve(newPdfManager);
pdfManagerCapability.resolve(newPdfManager);
cancelXHRs = null; cancelXHRs = null;
}) })
.catch(function (reason) { .catch(reason => {
pdfManagerCapability.reject(reason); reject(reason);
cancelXHRs = null; cancelXHRs = null;
}); });
new Promise(function (resolve, reject) { async function readData() {
const readChunk = function ({ value, done }) { let loaded = 0;
try {
while (true) {
const { value, done } = await fullReader.read();
ensureNotTerminated(); ensureNotTerminated();
if (done) { if (done) {
if (!newPdfManager) { break;
const pdfFile = arrayBuffersToBytes(cachedChunks);
cachedChunks = [];
if (length && pdfFile.length !== length) {
warn("reported HTTP length is different from actual");
}
pdfManagerArgs.source = pdfFile;
newPdfManager = new LocalPdfManager(pdfManagerArgs);
pdfManagerCapability.resolve(newPdfManager);
}
cancelXHRs = null;
return;
} }
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) { if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert( assert(
value instanceof ArrayBuffer, value instanceof ArrayBuffer,
"readChunk (getPdfManager) - expected an ArrayBuffer." "readData (getPdfManager) - expected an ArrayBuffer."
); );
} }
loaded += value.byteLength; loaded += value.byteLength;
@ -294,22 +284,28 @@ class WorkerMessageHandler {
} else { } else {
cachedChunks.push(value); cachedChunks.push(value);
} }
fullReader.read().then(readChunk, reject);
} catch (e) {
reject(e);
} }
};
fullReader.read().then(readChunk, reject); if (!newPdfManager) {
}).catch(function (e) { const pdfFile = arrayBuffersToBytes(cachedChunks);
pdfManagerCapability.reject(e); cachedChunks = null;
if (length && pdfFile.length !== length) {
warn("reported HTTP length is different from actual");
}
pdfManagerArgs.source = pdfFile;
newPdfManager = new LocalPdfManager(pdfManagerArgs);
resolve(newPdfManager);
}
cancelXHRs = null;
}
readData().catch(reason => {
reject(reason);
cancelXHRs = null; cancelXHRs = null;
}); });
cancelXHRs = reason => { return promise;
pdfStream.cancelAllRequests(reason);
};
return pdfManagerCapability.promise;
} }
function setupDoc(data) { function setupDoc(data) {
@ -960,7 +956,7 @@ class WorkerMessageHandler {
return pdfManager.cleanup(/* manuallyTriggered = */ true); return pdfManager.cleanup(/* manuallyTriggered = */ true);
}); });
handler.on("Terminate", function (data) { handler.on("Terminate", async function (data) {
terminated = true; terminated = true;
const waitOn = []; const waitOn = [];
@ -981,13 +977,12 @@ class WorkerMessageHandler {
task.terminate(); task.terminate();
} }
return Promise.all(waitOn).then(function () { await Promise.all(waitOn);
// Notice that even if we destroying handler, resolved response promise // Notice that even if we destroying handler, resolved response promise
// must be sent back. // must be sent back.
handler.destroy(); handler.destroy();
handler = null; handler = null;
}); });
});
handler.on("Ready", function (data) { handler.on("Ready", function (data) {
setupDoc(docParams); setupDoc(docParams);