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 }),
fullReader = pdfStream.getFullReader();
const pdfManagerCapability = Promise.withResolvers();
const { promise, resolve, reject } = Promise.withResolvers();
let newPdfManager,
cachedChunks = [],
loaded = 0;
cachedChunks = [];
cancelXHRs = reason => pdfStream.cancelAllRequests(reason);
fullReader.headersReady
.then(function () {
.then(() => {
if (!fullReader.isRangeSupported) {
return;
}
@ -239,77 +239,73 @@ class WorkerMessageHandler {
newPdfManager = new NetworkPdfManager(pdfManagerArgs);
// 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.
for (const chunk of cachedChunks) {
newPdfManager.sendProgressiveData(chunk);
}
cachedChunks = null;
cachedChunks = [];
pdfManagerCapability.resolve(newPdfManager);
resolve(newPdfManager);
cancelXHRs = null;
})
.catch(function (reason) {
pdfManagerCapability.reject(reason);
.catch(reason => {
reject(reason);
cancelXHRs = null;
});
new Promise(function (resolve, reject) {
const readChunk = function ({ value, done }) {
try {
ensureNotTerminated();
if (done) {
if (!newPdfManager) {
const pdfFile = arrayBuffersToBytes(cachedChunks);
cachedChunks = [];
async function readData() {
let loaded = 0;
if (length && pdfFile.length !== length) {
warn("reported HTTP length is different from actual");
}
pdfManagerArgs.source = pdfFile;
while (true) {
const { value, done } = await fullReader.read();
ensureNotTerminated();
newPdfManager = new LocalPdfManager(pdfManagerArgs);
pdfManagerCapability.resolve(newPdfManager);
}
cancelXHRs = null;
return;
}
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
value instanceof ArrayBuffer,
"readChunk (getPdfManager) - expected an ArrayBuffer."
);
}
loaded += value.byteLength;
if (!fullReader.isStreamingSupported) {
handler.send("DocProgress", {
loaded,
total: Math.max(loaded, fullReader.contentLength || 0),
});
}
if (newPdfManager) {
newPdfManager.sendProgressiveData(value);
} else {
cachedChunks.push(value);
}
fullReader.read().then(readChunk, reject);
} catch (e) {
reject(e);
if (done) {
break;
}
};
fullReader.read().then(readChunk, reject);
}).catch(function (e) {
pdfManagerCapability.reject(e);
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
value instanceof ArrayBuffer,
"readData (getPdfManager) - expected an ArrayBuffer."
);
}
loaded += value.byteLength;
if (!fullReader.isStreamingSupported) {
handler.send("DocProgress", {
loaded,
total: Math.max(loaded, fullReader.contentLength || 0),
});
}
if (newPdfManager) {
newPdfManager.sendProgressiveData(value);
} else {
cachedChunks.push(value);
}
}
if (!newPdfManager) {
const pdfFile = arrayBuffersToBytes(cachedChunks);
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 = reason => {
pdfStream.cancelAllRequests(reason);
};
return pdfManagerCapability.promise;
return promise;
}
function setupDoc(data) {
@ -960,7 +956,7 @@ class WorkerMessageHandler {
return pdfManager.cleanup(/* manuallyTriggered = */ true);
});
handler.on("Terminate", function (data) {
handler.on("Terminate", async function (data) {
terminated = true;
const waitOn = [];
@ -981,12 +977,11 @@ class WorkerMessageHandler {
task.terminate();
}
return Promise.all(waitOn).then(function () {
// Notice that even if we destroying handler, resolved response promise
// must be sent back.
handler.destroy();
handler = null;
});
await Promise.all(waitOn);
// Notice that even if we destroying handler, resolved response promise
// must be sent back.
handler.destroy();
handler = null;
});
handler.on("Ready", function (data) {