Convert the data reading in getPdfManager to be asynchronous

This is not only shorter, but (in my opinion) it also simplifies the code.

*Note:* In order to keep the *five* different `BasePDFStreamReader` implementations consistent, we purposely don't re-factor the `PDFWorkerStreamReader` class to support `for await...of` iteration.
This commit is contained in:
Jonas Jenwald 2026-02-15 14:47:45 +01:00
parent a4fcd830cc
commit e8ab3cb335

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) {