[api-minor] Replace the PromiseCapability with Promise.withResolvers()

This replaces our custom `PromiseCapability`-class with the new native `Promise.withResolvers()` functionality, which does *almost* the same thing[1]; please see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers

The only difference is that `PromiseCapability` also had a `settled`-getter, which was however not widely used and the call-sites can either be removed or re-factored to avoid it. In particular:
 - In `src/display/api.js` we can tweak the `PDFObjects`-class to use a "special" initial data-value and just compare against that, in order to replace the `settled`-state.
 - In `web/app.js` we change the only case to manually track the `settled`-state, which should hopefully be OK given how this is being used.
 - In `web/pdf_outline_viewer.js` we can remove the `settled`-checks, since the code should work just fine without it. The only thing that could potentially happen is that we try to `resolve` a Promise multiple times, which is however *not* a problem since the value of a Promise cannot be changed once fulfilled or rejected.
 - In `web/pdf_viewer.js` we can remove the `settled`-checks, since the code should work fine without them:
     - For the `_onePageRenderedCapability` case the `settled`-check is used in a `EventBus`-listener which is *removed* on its first (valid) invocation.
     - For the `_pagesCapability` case the `settled`-check is used in a print-related helper that works just fine with "only" the other checks.
 - In `test/unit/api_spec.js` we can change the few relevant cases to manually track the `settled`-state, since this is both simple and *test-only* code.

---
[1] In browsers/environments that lack native support, note [the compatibility data](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers#browser_compatibility), it'll be polyfilled via the `core-js` library (but only in `legacy` builds).
This commit is contained in:
Jonas Jenwald 2024-03-28 16:42:37 +01:00
parent 55db43966e
commit e4d0e84802
28 changed files with 159 additions and 252 deletions

View file

@ -99,6 +99,13 @@ const AUTOPREFIXER_CONFIG = {
// Default Babel targets used for generic, components, minified-pre // Default Babel targets used for generic, components, minified-pre
const BABEL_TARGETS = ENV_TARGETS.join(", "); const BABEL_TARGETS = ENV_TARGETS.join(", ");
const BABEL_PRESET_ENV_OPTS = Object.freeze({
corejs: "3.36.1",
exclude: ["web.structured-clone"],
shippedProposals: true,
useBuiltIns: "usage",
});
const DEFINES = Object.freeze({ const DEFINES = Object.freeze({
SKIP_BABEL: true, SKIP_BABEL: true,
TESTING: undefined, TESTING: undefined,
@ -303,17 +310,7 @@ function createWebpackConfig(
const babelPresets = skipBabel const babelPresets = skipBabel
? undefined ? undefined
: [ : [["@babel/preset-env", BABEL_PRESET_ENV_OPTS]];
[
"@babel/preset-env",
{
corejs: "3.36.1",
exclude: ["web.structured-clone"],
shippedProposals: true,
useBuiltIns: "usage",
},
],
];
const babelPlugins = [ const babelPlugins = [
[ [
babelPluginPDFJSPreprocessor, babelPluginPDFJSPreprocessor,
@ -1542,7 +1539,12 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
sourceType: "module", sourceType: "module",
presets: skipBabel presets: skipBabel
? undefined ? undefined
: [["@babel/preset-env", { loose: false, modules: false }]], : [
[
"@babel/preset-env",
{ ...BABEL_PRESET_ENV_OPTS, loose: false, modules: false },
],
],
plugins: [[babelPluginPDFJSPreprocessor, ctx]], plugins: [[babelPluginPDFJSPreprocessor, ctx]],
targets: BABEL_TARGETS, targets: BABEL_TARGETS,
}).code; }).code;

View file

@ -14,7 +14,7 @@
*/ */
import { arrayBuffersToBytes, MissingDataException } from "./core_utils.js"; import { arrayBuffersToBytes, MissingDataException } from "./core_utils.js";
import { assert, PromiseCapability } from "../shared/util.js"; import { assert } from "../shared/util.js";
import { Stream } from "./stream.js"; import { Stream } from "./stream.js";
class ChunkedStream extends Stream { class ChunkedStream extends Stream {
@ -273,7 +273,7 @@ class ChunkedStreamManager {
this.progressiveDataLength = 0; this.progressiveDataLength = 0;
this.aborted = false; this.aborted = false;
this._loadedStreamCapability = new PromiseCapability(); this._loadedStreamCapability = Promise.withResolvers();
} }
sendRequest(begin, end) { sendRequest(begin, end) {
@ -347,7 +347,7 @@ class ChunkedStreamManager {
return Promise.resolve(); return Promise.resolve();
} }
const capability = new PromiseCapability(); const capability = Promise.withResolvers();
this._promisesByRequest.set(requestId, capability); this._promisesByRequest.set(requestId, capability);
const chunksToRequest = []; const chunksToRequest = [];

View file

@ -25,7 +25,6 @@ import {
isArrayEqual, isArrayEqual,
normalizeUnicode, normalizeUnicode,
OPS, OPS,
PromiseCapability,
shadow, shadow,
stringToPDFString, stringToPDFString,
TextRenderingMode, TextRenderingMode,
@ -1270,7 +1269,7 @@ class PartialEvaluator {
return this.fontCache.get(font.cacheKey); return this.fontCache.get(font.cacheKey);
} }
const fontCapability = new PromiseCapability(); const { promise, resolve } = Promise.withResolvers();
let preEvaluatedFont; let preEvaluatedFont;
try { try {
@ -1328,10 +1327,10 @@ class PartialEvaluator {
// keys. Also, since `fontRef` is used when getting cached fonts, // keys. Also, since `fontRef` is used when getting cached fonts,
// we'll not accidentally match fonts cached with the `fontID`. // we'll not accidentally match fonts cached with the `fontID`.
if (fontRefIsRef) { if (fontRefIsRef) {
this.fontCache.put(fontRef, fontCapability.promise); this.fontCache.put(fontRef, promise);
} else { } else {
font.cacheKey = `cacheKey_${fontID}`; font.cacheKey = `cacheKey_${fontID}`;
this.fontCache.put(font.cacheKey, fontCapability.promise); this.fontCache.put(font.cacheKey, promise);
} }
// Keep track of each font we translated so the caller can // Keep track of each font we translated so the caller can
@ -1340,7 +1339,7 @@ class PartialEvaluator {
this.translateFont(preEvaluatedFont) this.translateFont(preEvaluatedFont)
.then(translatedFont => { .then(translatedFont => {
fontCapability.resolve( resolve(
new TranslatedFont({ new TranslatedFont({
loadedName: font.loadedName, loadedName: font.loadedName,
font: translatedFont, font: translatedFont,
@ -1350,10 +1349,10 @@ class PartialEvaluator {
); );
}) })
.catch(reason => { .catch(reason => {
// TODO fontCapability.reject? // TODO reject?
warn(`loadFont - translateFont failed: "${reason}".`); warn(`loadFont - translateFont failed: "${reason}".`);
fontCapability.resolve( resolve(
new TranslatedFont({ new TranslatedFont({
loadedName: font.loadedName, loadedName: font.loadedName,
font: new ErrorFont( font: new ErrorFont(
@ -1364,7 +1363,7 @@ class PartialEvaluator {
}) })
); );
}); });
return fontCapability.promise; return promise;
} }
buildPath(operatorList, fn, args, parsingText = false) { buildPath(operatorList, fn, args, parsingText = false) {

View file

@ -22,7 +22,6 @@ import {
isNodeJS, isNodeJS,
MissingPDFException, MissingPDFException,
PasswordException, PasswordException,
PromiseCapability,
setVerbosityLevel, setVerbosityLevel,
stringToPDFString, stringToPDFString,
UnexpectedResponseException, UnexpectedResponseException,
@ -48,7 +47,7 @@ class WorkerTask {
constructor(name) { constructor(name) {
this.name = name; this.name = name;
this.terminated = false; this.terminated = false;
this._capability = new PromiseCapability(); this._capability = Promise.withResolvers();
} }
get finished() { get finished() {
@ -212,7 +211,7 @@ class WorkerMessageHandler {
password, password,
rangeChunkSize, rangeChunkSize,
}; };
const pdfManagerCapability = new PromiseCapability(); const pdfManagerCapability = Promise.withResolvers();
let newPdfManager; let newPdfManager;
if (data) { if (data) {

View file

@ -28,7 +28,6 @@ import {
MAX_IMAGE_SIZE_TO_CACHE, MAX_IMAGE_SIZE_TO_CACHE,
MissingPDFException, MissingPDFException,
PasswordException, PasswordException,
PromiseCapability,
RenderingIntentFlag, RenderingIntentFlag,
setVerbosityLevel, setVerbosityLevel,
shadow, shadow,
@ -577,7 +576,7 @@ class PDFDocumentLoadingTask {
static #docId = 0; static #docId = 0;
constructor() { constructor() {
this._capability = new PromiseCapability(); this._capability = Promise.withResolvers();
this._transport = null; this._transport = null;
this._worker = null; this._worker = null;
@ -674,7 +673,7 @@ class PDFDataRangeTransport {
this._progressListeners = []; this._progressListeners = [];
this._progressiveReadListeners = []; this._progressiveReadListeners = [];
this._progressiveDoneListeners = []; this._progressiveDoneListeners = [];
this._readyCapability = new PromiseCapability(); this._readyCapability = Promise.withResolvers();
} }
/** /**
@ -1461,7 +1460,7 @@ class PDFPageProxy {
// If there's no displayReadyCapability yet, then the operatorList // If there's no displayReadyCapability yet, then the operatorList
// was never requested before. Make the request and create the promise. // was never requested before. Make the request and create the promise.
if (!intentState.displayReadyCapability) { if (!intentState.displayReadyCapability) {
intentState.displayReadyCapability = new PromiseCapability(); intentState.displayReadyCapability = Promise.withResolvers();
intentState.operatorList = { intentState.operatorList = {
fnArray: [], fnArray: [],
argsArray: [], argsArray: [],
@ -1588,7 +1587,7 @@ class PDFPageProxy {
if (!intentState.opListReadCapability) { if (!intentState.opListReadCapability) {
opListTask = Object.create(null); opListTask = Object.create(null);
opListTask.operatorListChanged = operatorListChanged; opListTask.operatorListChanged = operatorListChanged;
intentState.opListReadCapability = new PromiseCapability(); intentState.opListReadCapability = Promise.withResolvers();
(intentState.renderTasks ||= new Set()).add(opListTask); (intentState.renderTasks ||= new Set()).add(opListTask);
intentState.operatorList = { intentState.operatorList = {
fnArray: [], fnArray: [],
@ -2049,7 +2048,7 @@ class PDFWorker {
this.destroyed = false; this.destroyed = false;
this.verbosity = verbosity; this.verbosity = verbosity;
this._readyCapability = new PromiseCapability(); this._readyCapability = Promise.withResolvers();
this._port = null; this._port = null;
this._webWorker = null; this._webWorker = null;
this._messageHandler = null; this._messageHandler = null;
@ -2365,7 +2364,7 @@ class WorkerTransport {
this._networkStream = networkStream; this._networkStream = networkStream;
this._fullReader = null; this._fullReader = null;
this._lastProgress = null; this._lastProgress = null;
this.downloadInfoCapability = new PromiseCapability(); this.downloadInfoCapability = Promise.withResolvers();
this.setupMessageHandler(); this.setupMessageHandler();
@ -2471,7 +2470,7 @@ class WorkerTransport {
} }
this.destroyed = true; this.destroyed = true;
this.destroyCapability = new PromiseCapability(); this.destroyCapability = Promise.withResolvers();
this.#passwordCapability?.reject( this.#passwordCapability?.reject(
new Error("Worker was destroyed during onPassword callback") new Error("Worker was destroyed during onPassword callback")
@ -2562,7 +2561,7 @@ class WorkerTransport {
}); });
messageHandler.on("ReaderHeadersReady", data => { messageHandler.on("ReaderHeadersReady", data => {
const headersCapability = new PromiseCapability(); const headersCapability = Promise.withResolvers();
const fullReader = this._fullReader; const fullReader = this._fullReader;
fullReader.headersReady.then(() => { fullReader.headersReady.then(() => {
// If stream or range are disabled, it's our only way to report // If stream or range are disabled, it's our only way to report
@ -2677,7 +2676,7 @@ class WorkerTransport {
}); });
messageHandler.on("PasswordRequest", exception => { messageHandler.on("PasswordRequest", exception => {
this.#passwordCapability = new PromiseCapability(); this.#passwordCapability = Promise.withResolvers();
if (loadingTask.onPassword) { if (loadingTask.onPassword) {
const updatePassword = password => { const updatePassword = password => {
@ -3089,6 +3088,8 @@ class WorkerTransport {
} }
} }
const INITIAL_DATA = Symbol("INITIAL_DATA");
/** /**
* A PDF document and page is built of many objects. E.g. there are objects for * A PDF document and page is built of many objects. E.g. there are objects for
* fonts, images, rendering code, etc. These objects may get processed inside of * fonts, images, rendering code, etc. These objects may get processed inside of
@ -3105,8 +3106,8 @@ class PDFObjects {
*/ */
#ensureObj(objId) { #ensureObj(objId) {
return (this.#objs[objId] ||= { return (this.#objs[objId] ||= {
capability: new PromiseCapability(), ...Promise.withResolvers(),
data: null, data: INITIAL_DATA,
}); });
} }
@ -3127,7 +3128,7 @@ class PDFObjects {
// not required to be resolved right now. // not required to be resolved right now.
if (callback) { if (callback) {
const obj = this.#ensureObj(objId); const obj = this.#ensureObj(objId);
obj.capability.promise.then(() => callback(obj.data)); obj.promise.then(() => callback(obj.data));
return null; return null;
} }
// If there isn't a callback, the user expects to get the resolved data // If there isn't a callback, the user expects to get the resolved data
@ -3135,7 +3136,7 @@ class PDFObjects {
const obj = this.#objs[objId]; const obj = this.#objs[objId];
// If there isn't an object yet or the object isn't resolved, then the // If there isn't an object yet or the object isn't resolved, then the
// data isn't ready yet! // data isn't ready yet!
if (!obj?.capability.settled) { if (!obj || obj.data === INITIAL_DATA) {
throw new Error(`Requesting object that isn't resolved yet ${objId}.`); throw new Error(`Requesting object that isn't resolved yet ${objId}.`);
} }
return obj.data; return obj.data;
@ -3147,7 +3148,7 @@ class PDFObjects {
*/ */
has(objId) { has(objId) {
const obj = this.#objs[objId]; const obj = this.#objs[objId];
return obj?.capability.settled ?? false; return !!obj && obj.data !== INITIAL_DATA;
} }
/** /**
@ -3159,7 +3160,7 @@ class PDFObjects {
resolve(objId, data = null) { resolve(objId, data = null) {
const obj = this.#ensureObj(objId); const obj = this.#ensureObj(objId);
obj.data = data; obj.data = data;
obj.capability.resolve(); obj.resolve();
} }
clear() { clear() {
@ -3172,9 +3173,9 @@ class PDFObjects {
*[Symbol.iterator]() { *[Symbol.iterator]() {
for (const objId in this.#objs) { for (const objId in this.#objs) {
const { capability, data } = this.#objs[objId]; const { data } = this.#objs[objId];
if (!capability.settled) { if (data === INITIAL_DATA) {
continue; continue;
} }
yield [objId, data]; yield [objId, data];
@ -3283,7 +3284,7 @@ class InternalRenderTask {
this._useRequestAnimationFrame = this._useRequestAnimationFrame =
useRequestAnimationFrame === true && typeof window !== "undefined"; useRequestAnimationFrame === true && typeof window !== "undefined";
this.cancelled = false; this.cancelled = false;
this.capability = new PromiseCapability(); this.capability = Promise.withResolvers();
this.task = new RenderTask(this); this.task = new RenderTask(this);
// caching this-bound methods // caching this-bound methods
this._cancelBound = this.cancel.bind(this); this._cancelBound = this.cancel.bind(this);

View file

@ -13,12 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { AbortException, assert, warn } from "../shared/util.js";
AbortException,
assert,
PromiseCapability,
warn,
} from "../shared/util.js";
import { import {
createResponseStatusError, createResponseStatusError,
extractFilenameFromHeader, extractFilenameFromHeader,
@ -118,7 +113,7 @@ class PDFFetchStreamReader {
const source = stream.source; const source = stream.source;
this._withCredentials = source.withCredentials || false; this._withCredentials = source.withCredentials || false;
this._contentLength = source.length; this._contentLength = source.length;
this._headersCapability = new PromiseCapability(); this._headersCapability = Promise.withResolvers();
this._disableRange = source.disableRange || false; this._disableRange = source.disableRange || false;
this._rangeChunkSize = source.rangeChunkSize; this._rangeChunkSize = source.rangeChunkSize;
if (!this._rangeChunkSize && !this._disableRange) { if (!this._rangeChunkSize && !this._disableRange) {
@ -223,7 +218,7 @@ class PDFFetchStreamRangeReader {
this._loaded = 0; this._loaded = 0;
const source = stream.source; const source = stream.source;
this._withCredentials = source.withCredentials || false; this._withCredentials = source.withCredentials || false;
this._readCapability = new PromiseCapability(); this._readCapability = Promise.withResolvers();
this._isStreamingSupported = !source.disableStream; this._isStreamingSupported = !source.disableStream;
this._abortController = new AbortController(); this._abortController = new AbortController();

View file

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert, PromiseCapability, stringToBytes } from "../shared/util.js"; import { assert, stringToBytes } from "../shared/util.js";
import { import {
createResponseStatusError, createResponseStatusError,
extractFilenameFromHeader, extractFilenameFromHeader,
@ -255,7 +255,7 @@ class PDFNetworkStreamFullRequestReader {
}; };
this._url = source.url; this._url = source.url;
this._fullRequestId = manager.requestFull(args); this._fullRequestId = manager.requestFull(args);
this._headersReceivedCapability = new PromiseCapability(); this._headersReceivedCapability = Promise.withResolvers();
this._disableRange = source.disableRange || false; this._disableRange = source.disableRange || false;
this._contentLength = source.length; // Optional this._contentLength = source.length; // Optional
this._rangeChunkSize = source.rangeChunkSize; this._rangeChunkSize = source.rangeChunkSize;
@ -375,7 +375,7 @@ class PDFNetworkStreamFullRequestReader {
if (this._done) { if (this._done) {
return { value: undefined, done: true }; return { value: undefined, done: true };
} }
const requestCapability = new PromiseCapability(); const requestCapability = Promise.withResolvers();
this._requests.push(requestCapability); this._requests.push(requestCapability);
return requestCapability.promise; return requestCapability.promise;
} }
@ -466,7 +466,7 @@ class PDFNetworkStreamRangeRequestReader {
if (this._done) { if (this._done) {
return { value: undefined, done: true }; return { value: undefined, done: true };
} }
const requestCapability = new PromiseCapability(); const requestCapability = Promise.withResolvers();
this._requests.push(requestCapability); this._requests.push(requestCapability);
return requestCapability.promise; return requestCapability.promise;
} }

View file

@ -18,7 +18,6 @@ import {
assert, assert,
isNodeJS, isNodeJS,
MissingPDFException, MissingPDFException,
PromiseCapability,
} from "../shared/util.js"; } from "../shared/util.js";
import { import {
extractFilenameFromHeader, extractFilenameFromHeader,
@ -128,8 +127,8 @@ class BaseFullReader {
this._isRangeSupported = !source.disableRange; this._isRangeSupported = !source.disableRange;
this._readableStream = null; this._readableStream = null;
this._readCapability = new PromiseCapability(); this._readCapability = Promise.withResolvers();
this._headersCapability = new PromiseCapability(); this._headersCapability = Promise.withResolvers();
} }
get headersReady() { get headersReady() {
@ -163,7 +162,7 @@ class BaseFullReader {
const chunk = this._readableStream.read(); const chunk = this._readableStream.read();
if (chunk === null) { if (chunk === null) {
this._readCapability = new PromiseCapability(); this._readCapability = Promise.withResolvers();
return this.read(); return this.read();
} }
this._loaded += chunk.length; this._loaded += chunk.length;
@ -230,7 +229,7 @@ class BaseRangeReader {
this.onProgress = null; this.onProgress = null;
this._loaded = 0; this._loaded = 0;
this._readableStream = null; this._readableStream = null;
this._readCapability = new PromiseCapability(); this._readCapability = Promise.withResolvers();
const source = stream.source; const source = stream.source;
this._isStreamingSupported = !source.disableStream; this._isStreamingSupported = !source.disableStream;
} }
@ -250,7 +249,7 @@ class BaseRangeReader {
const chunk = this._readableStream.read(); const chunk = this._readableStream.read();
if (chunk === null) { if (chunk === null) {
this._readCapability = new PromiseCapability(); this._readCapability = Promise.withResolvers();
return this.read(); return this.read();
} }
this._loaded += chunk.length; this._loaded += chunk.length;

View file

@ -16,7 +16,7 @@
/** @typedef {import("./display_utils").PageViewport} PageViewport */ /** @typedef {import("./display_utils").PageViewport} PageViewport */
/** @typedef {import("./api").TextContent} TextContent */ /** @typedef {import("./api").TextContent} TextContent */
import { AbortException, PromiseCapability, Util } from "../shared/util.js"; import { AbortException, Util } from "../shared/util.js";
import { setLayerDimensions } from "./display_utils.js"; import { setLayerDimensions } from "./display_utils.js";
/** /**
@ -326,7 +326,7 @@ class TextLayerRenderTask {
this._reader = null; this._reader = null;
this._textDivProperties = textDivProperties || new WeakMap(); this._textDivProperties = textDivProperties || new WeakMap();
this._canceled = false; this._canceled = false;
this._capability = new PromiseCapability(); this._capability = Promise.withResolvers();
this._layoutTextParams = { this._layoutTextParams = {
prevFontSize: null, prevFontSize: null,
prevFontFamily: null, prevFontFamily: null,
@ -426,21 +426,21 @@ class TextLayerRenderTask {
* @private * @private
*/ */
_render() { _render() {
const capability = new PromiseCapability(); const { promise, resolve, reject } = Promise.withResolvers();
let styleCache = Object.create(null); let styleCache = Object.create(null);
if (this._isReadableStream) { if (this._isReadableStream) {
const pump = () => { const pump = () => {
this._reader.read().then(({ value, done }) => { this._reader.read().then(({ value, done }) => {
if (done) { if (done) {
capability.resolve(); resolve();
return; return;
} }
Object.assign(styleCache, value.styles); Object.assign(styleCache, value.styles);
this._processItems(value.items, styleCache); this._processItems(value.items, styleCache);
pump(); pump();
}, capability.reject); }, reject);
}; };
this._reader = this._textContentSource.getReader(); this._reader = this._textContentSource.getReader();
@ -448,12 +448,12 @@ class TextLayerRenderTask {
} else if (this._textContentSource) { } else if (this._textContentSource) {
const { items, styles } = this._textContentSource; const { items, styles } = this._textContentSource;
this._processItems(items, styles); this._processItems(items, styles);
capability.resolve(); resolve();
} else { } else {
throw new Error('No "textContentSource" parameter specified.'); throw new Error('No "textContentSource" parameter specified.');
} }
capability.promise.then(() => { promise.then(() => {
styleCache = null; styleCache = null;
render(this); render(this);
}, this._capability.reject); }, this._capability.reject);

View file

@ -18,7 +18,7 @@
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
/** @typedef {import("../interfaces").IPDFStreamRangeReader} IPDFStreamRangeReader */ /** @typedef {import("../interfaces").IPDFStreamRangeReader} IPDFStreamRangeReader */
import { assert, PromiseCapability } from "../shared/util.js"; import { assert } from "../shared/util.js";
import { isPdfFile } from "./display_utils.js"; import { isPdfFile } from "./display_utils.js";
/** @implements {IPDFStream} */ /** @implements {IPDFStream} */
@ -235,7 +235,7 @@ class PDFDataTransportStreamReader {
if (this._done) { if (this._done) {
return { value: undefined, done: true }; return { value: undefined, done: true };
} }
const requestCapability = new PromiseCapability(); const requestCapability = Promise.withResolvers();
this._requests.push(requestCapability); this._requests.push(requestCapability);
return requestCapability.promise; return requestCapability.promise;
} }
@ -300,7 +300,7 @@ class PDFDataTransportStreamRangeReader {
if (this._done) { if (this._done) {
return { value: undefined, done: true }; return { value: undefined, done: true };
} }
const requestCapability = new PromiseCapability(); const requestCapability = Promise.withResolvers();
this._requests.push(requestCapability); this._requests.push(requestCapability);
return requestCapability.promise; return requestCapability.promise;
} }

View file

@ -39,7 +39,6 @@ import {
OPS, OPS,
PasswordResponses, PasswordResponses,
PermissionFlag, PermissionFlag,
PromiseCapability,
shadow, shadow,
UnexpectedResponseException, UnexpectedResponseException,
Util, Util,
@ -119,7 +118,6 @@ export {
PDFWorker, PDFWorker,
PermissionFlag, PermissionFlag,
PixelsPerInch, PixelsPerInch,
PromiseCapability,
RenderingCancelledException, RenderingCancelledException,
renderTextLayer, renderTextLayer,
setLayerDimensions, setLayerDimensions,

View file

@ -18,7 +18,6 @@ import {
assert, assert,
MissingPDFException, MissingPDFException,
PasswordException, PasswordException,
PromiseCapability,
UnexpectedResponseException, UnexpectedResponseException,
UnknownErrorException, UnknownErrorException,
unreachable, unreachable,
@ -190,7 +189,7 @@ class MessageHandler {
*/ */
sendWithPromise(actionName, data, transfers) { sendWithPromise(actionName, data, transfers) {
const callbackId = this.callbackId++; const callbackId = this.callbackId++;
const capability = new PromiseCapability(); const capability = Promise.withResolvers();
this.callbackCapabilities[callbackId] = capability; this.callbackCapabilities[callbackId] = capability;
try { try {
this.comObj.postMessage( this.comObj.postMessage(
@ -228,7 +227,7 @@ class MessageHandler {
return new ReadableStream( return new ReadableStream(
{ {
start: controller => { start: controller => {
const startCapability = new PromiseCapability(); const startCapability = Promise.withResolvers();
this.streamControllers[streamId] = { this.streamControllers[streamId] = {
controller, controller,
startCall: startCapability, startCall: startCapability,
@ -252,7 +251,7 @@ class MessageHandler {
}, },
pull: controller => { pull: controller => {
const pullCapability = new PromiseCapability(); const pullCapability = Promise.withResolvers();
this.streamControllers[streamId].pullCall = pullCapability; this.streamControllers[streamId].pullCall = pullCapability;
comObj.postMessage({ comObj.postMessage({
sourceName, sourceName,
@ -268,7 +267,7 @@ class MessageHandler {
cancel: reason => { cancel: reason => {
assert(reason instanceof Error, "cancel must have a valid reason"); assert(reason instanceof Error, "cancel must have a valid reason");
const cancelCapability = new PromiseCapability(); const cancelCapability = Promise.withResolvers();
this.streamControllers[streamId].cancelCall = cancelCapability; this.streamControllers[streamId].cancelCall = cancelCapability;
this.streamControllers[streamId].isClosed = true; this.streamControllers[streamId].isClosed = true;
comObj.postMessage({ comObj.postMessage({
@ -305,7 +304,7 @@ class MessageHandler {
// so when it changes from positive to negative, // so when it changes from positive to negative,
// set ready as unresolved promise. // set ready as unresolved promise.
if (lastDesiredSize > 0 && this.desiredSize <= 0) { if (lastDesiredSize > 0 && this.desiredSize <= 0) {
this.sinkCapability = new PromiseCapability(); this.sinkCapability = Promise.withResolvers();
this.ready = this.sinkCapability.promise; this.ready = this.sinkCapability.promise;
} }
comObj.postMessage( comObj.postMessage(
@ -349,7 +348,7 @@ class MessageHandler {
}); });
}, },
sinkCapability: new PromiseCapability(), sinkCapability: Promise.withResolvers(),
onPull: null, onPull: null,
onCancel: null, onCancel: null,
isCancelled: false, isCancelled: false,

View file

@ -1031,43 +1031,6 @@ function getModificationDate(date = new Date()) {
return buffer.join(""); return buffer.join("");
} }
class PromiseCapability {
#settled = false;
constructor() {
/**
* @type {Promise<any>} The Promise object.
*/
this.promise = new Promise((resolve, reject) => {
/**
* @type {function} Fulfills the Promise.
*/
this.resolve = data => {
this.#settled = true;
resolve(data);
};
/**
* @type {function} Rejects the Promise.
*/
this.reject = reason => {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(reason instanceof Error, 'Expected valid "reason" argument.');
}
this.#settled = true;
reject(reason);
};
});
}
/**
* @type {boolean} If the Promise has been fulfilled/rejected.
*/
get settled() {
return this.#settled;
}
}
let NormalizeRegex = null; let NormalizeRegex = null;
let NormalizationMap = null; let NormalizationMap = null;
function normalizeUnicode(str) { function normalizeUnicode(str) {
@ -1154,7 +1117,6 @@ export {
PasswordException, PasswordException,
PasswordResponses, PasswordResponses,
PermissionFlag, PermissionFlag,
PromiseCapability,
RenderingIntentFlag, RenderingIntentFlag,
setVerbosityLevel, setVerbosityLevel,
shadow, shadow,

View file

@ -22,7 +22,6 @@ const {
GlobalWorkerOptions, GlobalWorkerOptions,
Outliner, Outliner,
PixelsPerInch, PixelsPerInch,
PromiseCapability,
renderTextLayer, renderTextLayer,
shadow, shadow,
XfaLayer, XfaLayer,
@ -1112,7 +1111,7 @@ class Driver {
} }
_send(url, message) { _send(url, message) {
const capability = new PromiseCapability(); const { promise, resolve } = Promise.withResolvers();
this.inflight.textContent = this.inFlightRequests++; this.inflight.textContent = this.inFlightRequests++;
fetch(url, { fetch(url, {
@ -1129,18 +1128,18 @@ class Driver {
} }
this.inFlightRequests--; this.inFlightRequests--;
capability.resolve(); resolve();
}) })
.catch(reason => { .catch(reason => {
console.warn(`Driver._send failed (${url}): ${reason}`); console.warn(`Driver._send failed (${url}): ${reason}`);
this.inFlightRequests--; this.inFlightRequests--;
capability.resolve(); resolve();
this._send(url, message); this._send(url, message);
}); });
return capability.promise; return promise;
} }
} }

View file

@ -26,7 +26,6 @@ import {
PasswordException, PasswordException,
PasswordResponses, PasswordResponses,
PermissionFlag, PermissionFlag,
PromiseCapability,
UnknownErrorException, UnknownErrorException,
} from "../../src/shared/util.js"; } from "../../src/shared/util.js";
import { import {
@ -156,13 +155,11 @@ describe("api", function () {
const loadingTask = getDocument(basicApiGetDocumentParams); const loadingTask = getDocument(basicApiGetDocumentParams);
expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true); expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true);
const progressReportedCapability = new PromiseCapability(); const progressReportedCapability = Promise.withResolvers();
// Attach the callback that is used to report loading progress; // Attach the callback that is used to report loading progress;
// similarly to how viewer.js works. // similarly to how viewer.js works.
loadingTask.onProgress = function (progressData) { loadingTask.onProgress = function (progressData) {
if (!progressReportedCapability.settled) { progressReportedCapability.resolve(progressData);
progressReportedCapability.resolve(progressData);
}
}; };
const data = await Promise.all([ const data = await Promise.all([
@ -218,7 +215,7 @@ describe("api", function () {
const loadingTask = getDocument(typedArrayPdf); const loadingTask = getDocument(typedArrayPdf);
expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true); expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true);
const progressReportedCapability = new PromiseCapability(); const progressReportedCapability = Promise.withResolvers();
loadingTask.onProgress = function (data) { loadingTask.onProgress = function (data) {
progressReportedCapability.resolve(data); progressReportedCapability.resolve(data);
}; };
@ -248,7 +245,7 @@ describe("api", function () {
const loadingTask = getDocument(arrayBufferPdf); const loadingTask = getDocument(arrayBufferPdf);
expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true); expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true);
const progressReportedCapability = new PromiseCapability(); const progressReportedCapability = Promise.withResolvers();
loadingTask.onProgress = function (data) { loadingTask.onProgress = function (data) {
progressReportedCapability.resolve(data); progressReportedCapability.resolve(data);
}; };
@ -306,8 +303,14 @@ describe("api", function () {
const loadingTask = getDocument(buildGetDocumentParams("pr6531_1.pdf")); const loadingTask = getDocument(buildGetDocumentParams("pr6531_1.pdf"));
expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true); expect(loadingTask instanceof PDFDocumentLoadingTask).toEqual(true);
const passwordNeededCapability = new PromiseCapability(); const passwordNeededCapability = {
const passwordIncorrectCapability = new PromiseCapability(); ...Promise.withResolvers(),
settled: false,
};
const passwordIncorrectCapability = {
...Promise.withResolvers(),
settled: false,
};
// Attach the callback that is used to request a password; // Attach the callback that is used to request a password;
// similarly to how the default viewer handles passwords. // similarly to how the default viewer handles passwords.
loadingTask.onPassword = function (updatePassword, reason) { loadingTask.onPassword = function (updatePassword, reason) {
@ -315,6 +318,7 @@ describe("api", function () {
reason === PasswordResponses.NEED_PASSWORD && reason === PasswordResponses.NEED_PASSWORD &&
!passwordNeededCapability.settled !passwordNeededCapability.settled
) { ) {
passwordNeededCapability.settled = true;
passwordNeededCapability.resolve(); passwordNeededCapability.resolve();
updatePassword("qwerty"); // Provide an incorrect password. updatePassword("qwerty"); // Provide an incorrect password.
@ -324,6 +328,7 @@ describe("api", function () {
reason === PasswordResponses.INCORRECT_PASSWORD && reason === PasswordResponses.INCORRECT_PASSWORD &&
!passwordIncorrectCapability.settled !passwordIncorrectCapability.settled
) { ) {
passwordIncorrectCapability.settled = true;
passwordIncorrectCapability.resolve(); passwordIncorrectCapability.resolve();
updatePassword("asdfasdf"); // Provide the correct password. updatePassword("asdfasdf"); // Provide the correct password.

View file

@ -15,7 +15,6 @@
import { import {
AbortException, AbortException,
PromiseCapability,
UnknownErrorException, UnknownErrorException,
} from "../../src/shared/util.js"; } from "../../src/shared/util.js";
import { LoopbackPort } from "../../src/display/api.js"; import { LoopbackPort } from "../../src/display/api.js";
@ -336,7 +335,7 @@ describe("message_handler", function () {
it("should ignore any pull after close is called", async function () { it("should ignore any pull after close is called", async function () {
let log = ""; let log = "";
const port = new LoopbackPort(); const port = new LoopbackPort();
const capability = new PromiseCapability(); const { promise, resolve } = Promise.withResolvers();
const messageHandler2 = new MessageHandler("worker", "main", port); const messageHandler2 = new MessageHandler("worker", "main", port);
messageHandler2.on("fakeHandler", (data, sink) => { messageHandler2.on("fakeHandler", (data, sink) => {
sink.onPull = function () { sink.onPull = function () {
@ -350,7 +349,7 @@ describe("message_handler", function () {
log += "1"; log += "1";
sink.enqueue([1, 2, 3, 4], 4); sink.enqueue([1, 2, 3, 4], 4);
}); });
return capability.promise.then(() => { return promise.then(() => {
sink.close(); sink.close();
}); });
}); });
@ -371,8 +370,8 @@ describe("message_handler", function () {
await sleep(10); await sleep(10);
expect(log).toEqual("01"); expect(log).toEqual("01");
capability.resolve(); resolve();
await capability.promise; await promise;
let result = await reader.read(); let result = await reader.read();
expect(result.value).toEqual([1, 2, 3, 4]); expect(result.value).toEqual([1, 2, 3, 4]);

View file

@ -29,7 +29,6 @@ import {
OPS, OPS,
PasswordResponses, PasswordResponses,
PermissionFlag, PermissionFlag,
PromiseCapability,
shadow, shadow,
UnexpectedResponseException, UnexpectedResponseException,
Util, Util,
@ -105,7 +104,6 @@ const expectedAPI = Object.freeze({
PDFWorker, PDFWorker,
PermissionFlag, PermissionFlag,
PixelsPerInch, PixelsPerInch,
PromiseCapability,
RenderingCancelledException, RenderingCancelledException,
renderTextLayer, renderTextLayer,
setLayerDimensions, setLayerDimensions,

View file

@ -17,7 +17,6 @@ import {
bytesToString, bytesToString,
createValidAbsoluteUrl, createValidAbsoluteUrl,
getModificationDate, getModificationDate,
PromiseCapability,
string32, string32,
stringToBytes, stringToBytes,
stringToPDFString, stringToPDFString,
@ -223,37 +222,6 @@ describe("util", function () {
}); });
}); });
describe("PromiseCapability", function () {
it("should resolve with correct data", async function () {
const promiseCapability = new PromiseCapability();
expect(promiseCapability.settled).toEqual(false);
promiseCapability.resolve({ test: "abc" });
const data = await promiseCapability.promise;
expect(promiseCapability.settled).toEqual(true);
expect(data).toEqual({ test: "abc" });
});
it("should reject with correct reason", async function () {
const promiseCapability = new PromiseCapability();
expect(promiseCapability.settled).toEqual(false);
promiseCapability.reject(new Error("reason"));
try {
await promiseCapability.promise;
// Shouldn't get here.
expect(false).toEqual(true);
} catch (reason) {
expect(promiseCapability.settled).toEqual(true);
expect(reason instanceof Error).toEqual(true);
expect(reason.message).toEqual("reason");
}
});
});
describe("getModificationDate", function () { describe("getModificationDate", function () {
it("should get a correctly formatted date", function () { it("should get a correctly formatted date", function () {
const date = new Date(Date.UTC(3141, 5, 9, 2, 6, 53)); const date = new Date(Date.UTC(3141, 5, 9, 2, 6, 53));

View file

@ -46,7 +46,6 @@ import {
isPdfFile, isPdfFile,
MissingPDFException, MissingPDFException,
PDFWorker, PDFWorker,
PromiseCapability,
shadow, shadow,
UnexpectedResponseException, UnexpectedResponseException,
version, version,
@ -92,7 +91,10 @@ const ViewOnLoad = {
const PDFViewerApplication = { const PDFViewerApplication = {
initialBookmark: document.location.hash.substring(1), initialBookmark: document.location.hash.substring(1),
_initializedCapability: new PromiseCapability(), _initializedCapability: {
...Promise.withResolvers(),
settled: false,
},
appConfig: null, appConfig: null,
pdfDocument: null, pdfDocument: null,
pdfLoadingTask: null, pdfLoadingTask: null,
@ -240,6 +242,7 @@ const PDFViewerApplication = {
this.bindEvents(); this.bindEvents();
this.bindWindowEvents(); this.bindWindowEvents();
this._initializedCapability.settled = true;
this._initializedCapability.resolve(); this._initializedCapability.resolve();
}, },

View file

@ -35,39 +35,40 @@ const WaitOnType = {
* @param {WaitOnEventOrTimeoutParameters} * @param {WaitOnEventOrTimeoutParameters}
* @returns {Promise} A promise that is resolved with a {WaitOnType} value. * @returns {Promise} A promise that is resolved with a {WaitOnType} value.
*/ */
function waitOnEventOrTimeout({ target, name, delay = 0 }) { async function waitOnEventOrTimeout({ target, name, delay = 0 }) {
return new Promise(function (resolve, reject) { if (
if ( typeof target !== "object" ||
typeof target !== "object" || !(name && typeof name === "string") ||
!(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)
!(Number.isInteger(delay) && delay >= 0) ) {
) { throw new Error("waitOnEventOrTimeout - invalid parameters.");
throw new Error("waitOnEventOrTimeout - invalid parameters."); }
} const { promise, resolve } = Promise.withResolvers();
function handler(type) { function handler(type) {
if (target instanceof EventBus) {
target._off(name, eventHandler);
} else {
target.removeEventListener(name, eventHandler);
}
if (timeout) {
clearTimeout(timeout);
}
resolve(type);
}
const eventHandler = handler.bind(null, WaitOnType.EVENT);
if (target instanceof EventBus) { if (target instanceof EventBus) {
target._on(name, eventHandler); target._off(name, eventHandler);
} else { } else {
target.addEventListener(name, eventHandler); target.removeEventListener(name, eventHandler);
} }
const timeoutHandler = handler.bind(null, WaitOnType.TIMEOUT); if (timeout) {
const timeout = setTimeout(timeoutHandler, delay); clearTimeout(timeout);
}); }
resolve(type);
}
const eventHandler = handler.bind(null, WaitOnType.EVENT);
if (target instanceof EventBus) {
target._on(name, eventHandler);
} else {
target.addEventListener(name, eventHandler);
}
const timeoutHandler = handler.bind(null, WaitOnType.TIMEOUT);
const timeout = setTimeout(timeoutHandler, delay);
return promise;
} }
/** /**

View file

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { PasswordResponses, PromiseCapability } from "pdfjs-lib"; import { PasswordResponses } from "pdfjs-lib";
/** /**
* @typedef {Object} PasswordPromptOptions * @typedef {Object} PasswordPromptOptions
@ -64,10 +64,8 @@ class PasswordPrompt {
} }
async open() { async open() {
if (this.#activeCapability) { await this.#activeCapability?.promise;
await this.#activeCapability.promise; this.#activeCapability = Promise.withResolvers();
}
this.#activeCapability = new PromiseCapability();
try { try {
await this.overlayManager.open(this.dialog); await this.overlayManager.open(this.dialog);

View file

@ -13,8 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { getFilenameFromUrl, PromiseCapability } from "pdfjs-lib";
import { BaseTreeViewer } from "./base_tree_viewer.js"; import { BaseTreeViewer } from "./base_tree_viewer.js";
import { getFilenameFromUrl } from "pdfjs-lib";
import { waitOnEventOrTimeout } from "./event_utils.js"; import { waitOnEventOrTimeout } from "./event_utils.js";
/** /**
@ -50,7 +50,7 @@ class PDFAttachmentViewer extends BaseTreeViewer {
if (!keepRenderedCapability) { if (!keepRenderedCapability) {
// The only situation in which the `_renderedCapability` should *not* be // The only situation in which the `_renderedCapability` should *not* be
// replaced is when appending FileAttachment annotations. // replaced is when appending FileAttachment annotations.
this._renderedCapability = new PromiseCapability(); this._renderedCapability = Promise.withResolvers();
} }
this._pendingDispatchEvent = false; this._pendingDispatchEvent = false;
} }

View file

@ -14,7 +14,7 @@
*/ */
import { getPageSizeInches, isPortraitOrientation } from "./ui_utils.js"; import { getPageSizeInches, isPortraitOrientation } from "./ui_utils.js";
import { PDFDateString, PromiseCapability } from "pdfjs-lib"; import { PDFDateString } from "pdfjs-lib";
const DEFAULT_FIELD_CONTENT = "-"; const DEFAULT_FIELD_CONTENT = "-";
@ -200,7 +200,7 @@ class PDFDocumentProperties {
this.pdfDocument = null; this.pdfDocument = null;
this.#fieldData = null; this.#fieldData = null;
this._dataAvailableCapability = new PromiseCapability(); this._dataAvailableCapability = Promise.withResolvers();
this._currentPageNumber = 1; this._currentPageNumber = 1;
this._pagesRotation = 0; this._pagesRotation = 0;
} }

View file

@ -19,7 +19,6 @@
import { binarySearchFirstItem, scrollIntoView } from "./ui_utils.js"; import { binarySearchFirstItem, scrollIntoView } from "./ui_utils.js";
import { getCharacterType, getNormalizeWithNFKC } from "./pdf_find_utils.js"; import { getCharacterType, getNormalizeWithNFKC } from "./pdf_find_utils.js";
import { PromiseCapability } from "pdfjs-lib";
const FindState = { const FindState = {
FOUND: 0, FOUND: 0,
@ -576,7 +575,7 @@ class PDFFindController {
clearTimeout(this._findTimeout); clearTimeout(this._findTimeout);
this._findTimeout = null; this._findTimeout = null;
this._firstPageCapability = new PromiseCapability(); this._firstPageCapability = Promise.withResolvers();
} }
/** /**
@ -836,14 +835,14 @@ class PDFFindController {
return; return;
} }
let promise = Promise.resolve(); let deferred = Promise.resolve();
const textOptions = { disableNormalization: true }; const textOptions = { disableNormalization: true };
for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) { for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) {
const extractTextCapability = new PromiseCapability(); const { promise, resolve } = Promise.withResolvers();
this._extractTextPromises[i] = extractTextCapability.promise; this._extractTextPromises[i] = promise;
// eslint-disable-next-line arrow-body-style // eslint-disable-next-line arrow-body-style
promise = promise.then(() => { deferred = deferred.then(() => {
return this._pdfDocument return this._pdfDocument
.getPage(i + 1) .getPage(i + 1)
.then(pdfPage => pdfPage.getTextContent(textOptions)) .then(pdfPage => pdfPage.getTextContent(textOptions))
@ -864,7 +863,7 @@ class PDFFindController {
this._pageDiffs[i], this._pageDiffs[i],
this._hasDiacritics[i], this._hasDiacritics[i],
] = normalize(strBuf.join("")); ] = normalize(strBuf.join(""));
extractTextCapability.resolve(); resolve();
}, },
reason => { reason => {
console.error( console.error(
@ -875,7 +874,7 @@ class PDFFindController {
this._pageContents[i] = ""; this._pageContents[i] = "";
this._pageDiffs[i] = null; this._pageDiffs[i] = null;
this._hasDiacritics[i] = false; this._hasDiacritics[i] = false;
extractTextCapability.resolve(); resolve();
} }
); );
}); });

View file

@ -14,7 +14,6 @@
*/ */
import { BaseTreeViewer } from "./base_tree_viewer.js"; import { BaseTreeViewer } from "./base_tree_viewer.js";
import { PromiseCapability } from "pdfjs-lib";
import { SidebarView } from "./ui_utils.js"; import { SidebarView } from "./ui_utils.js";
/** /**
@ -54,14 +53,9 @@ class PDFOutlineViewer extends BaseTreeViewer {
// If the capability is still pending, see the `_dispatchEvent`-method, // If the capability is still pending, see the `_dispatchEvent`-method,
// we know that the `currentOutlineItem`-button can be enabled here. // we know that the `currentOutlineItem`-button can be enabled here.
if ( this._currentOutlineItemCapability?.resolve(
this._currentOutlineItemCapability && /* enabled = */ this._isPagesLoaded
!this._currentOutlineItemCapability.settled );
) {
this._currentOutlineItemCapability.resolve(
/* enabled = */ this._isPagesLoaded
);
}
}); });
this.eventBus._on("sidebarviewchanged", evt => { this.eventBus._on("sidebarviewchanged", evt => {
this._sidebarView = evt.view; this._sidebarView = evt.view;
@ -76,12 +70,7 @@ class PDFOutlineViewer extends BaseTreeViewer {
this._currentPageNumber = 1; this._currentPageNumber = 1;
this._isPagesLoaded = null; this._isPagesLoaded = null;
if ( this._currentOutlineItemCapability?.resolve(/* enabled = */ false);
this._currentOutlineItemCapability &&
!this._currentOutlineItemCapability.settled
) {
this._currentOutlineItemCapability.resolve(/* enabled = */ false);
}
this._currentOutlineItemCapability = null; this._currentOutlineItemCapability = null;
} }
@ -89,7 +78,7 @@ class PDFOutlineViewer extends BaseTreeViewer {
* @private * @private
*/ */
_dispatchEvent(outlineCount) { _dispatchEvent(outlineCount) {
this._currentOutlineItemCapability = new PromiseCapability(); this._currentOutlineItemCapability = Promise.withResolvers();
if ( if (
outlineCount === 0 || outlineCount === 0 ||
this._pdfDocument?.loadingParams.disableAutoFetch this._pdfDocument?.loadingParams.disableAutoFetch
@ -307,7 +296,7 @@ class PDFOutlineViewer extends BaseTreeViewer {
if (this._pageNumberToDestHashCapability) { if (this._pageNumberToDestHashCapability) {
return this._pageNumberToDestHashCapability.promise; return this._pageNumberToDestHashCapability.promise;
} }
this._pageNumberToDestHashCapability = new PromiseCapability(); this._pageNumberToDestHashCapability = Promise.withResolvers();
const pageNumberToDestHash = new Map(), const pageNumberToDestHash = new Map(),
pageNumberNesting = new Map(); pageNumberNesting = new Map();

View file

@ -16,7 +16,7 @@
/** @typedef {import("./event_utils").EventBus} EventBus */ /** @typedef {import("./event_utils").EventBus} EventBus */
import { apiPageLayoutToViewerModes, RenderingStates } from "./ui_utils.js"; import { apiPageLayoutToViewerModes, RenderingStates } from "./ui_utils.js";
import { PromiseCapability, shadow } from "pdfjs-lib"; import { shadow } from "pdfjs-lib";
/** /**
* @typedef {Object} PDFScriptingManagerOptions * @typedef {Object} PDFScriptingManagerOptions
@ -199,7 +199,7 @@ class PDFScriptingManager {
return; return;
} }
await this.#willPrintCapability?.promise; await this.#willPrintCapability?.promise;
this.#willPrintCapability = new PromiseCapability(); this.#willPrintCapability = Promise.withResolvers();
try { try {
await this.#scripting.dispatchEventInSandbox({ await this.#scripting.dispatchEventInSandbox({
id: "doc", id: "doc",
@ -344,7 +344,7 @@ class PDFScriptingManager {
visitedPages = this._visitedPages; visitedPages = this._visitedPages;
if (initialize) { if (initialize) {
this.#closeCapability = new PromiseCapability(); this.#closeCapability = Promise.withResolvers();
} }
if (!this.#closeCapability) { if (!this.#closeCapability) {
return; // Scripting isn't fully initialized yet. return; // Scripting isn't fully initialized yet.
@ -406,7 +406,7 @@ class PDFScriptingManager {
} }
#initScripting() { #initScripting() {
this.#destroyCapability = new PromiseCapability(); this.#destroyCapability = Promise.withResolvers();
if (this.#scripting) { if (this.#scripting) {
throw new Error("#initScripting: Scripting already exists."); throw new Error("#initScripting: Scripting already exists.");

View file

@ -34,7 +34,6 @@ import {
AnnotationMode, AnnotationMode,
PermissionFlag, PermissionFlag,
PixelsPerInch, PixelsPerInch,
PromiseCapability,
shadow, shadow,
version, version,
} from "pdfjs-lib"; } from "pdfjs-lib";
@ -362,10 +361,7 @@ class PDFViewer {
get pageViewsReady() { get pageViewsReady() {
// Prevent printing errors when 'disableAutoFetch' is set, by ensuring // Prevent printing errors when 'disableAutoFetch' is set, by ensuring
// that *all* pages have in fact been completely loaded. // that *all* pages have in fact been completely loaded.
return ( return this._pages.every(pageView => pageView?.pdfPage);
this._pagesCapability.settled &&
this._pages.every(pageView => pageView?.pdfPage)
);
} }
/** /**
@ -823,7 +819,7 @@ class PDFViewer {
this.eventBus._on("pagerender", this._onBeforeDraw); this.eventBus._on("pagerender", this._onBeforeDraw);
this._onAfterDraw = evt => { this._onAfterDraw = evt => {
if (evt.cssTransform || this._onePageRenderedCapability.settled) { if (evt.cssTransform) {
return; return;
} }
this._onePageRenderedCapability.resolve({ timestamp: evt.timestamp }); this._onePageRenderedCapability.resolve({ timestamp: evt.timestamp });
@ -1075,9 +1071,9 @@ class PDFViewer {
this._location = null; this._location = null;
this._pagesRotation = 0; this._pagesRotation = 0;
this._optionalContentConfigPromise = null; this._optionalContentConfigPromise = null;
this._firstPageCapability = new PromiseCapability(); this._firstPageCapability = Promise.withResolvers();
this._onePageRenderedCapability = new PromiseCapability(); this._onePageRenderedCapability = Promise.withResolvers();
this._pagesCapability = new PromiseCapability(); this._pagesCapability = Promise.withResolvers();
this._scrollMode = ScrollMode.VERTICAL; this._scrollMode = ScrollMode.VERTICAL;
this._previousScrollMode = ScrollMode.UNKNOWN; this._previousScrollMode = ScrollMode.UNKNOWN;
this._spreadMode = SpreadMode.NONE; this._spreadMode = SpreadMode.NONE;

View file

@ -58,7 +58,6 @@ const {
PDFWorker, PDFWorker,
PermissionFlag, PermissionFlag,
PixelsPerInch, PixelsPerInch,
PromiseCapability,
RenderingCancelledException, RenderingCancelledException,
renderTextLayer, renderTextLayer,
setLayerDimensions, setLayerDimensions,
@ -107,7 +106,6 @@ export {
PDFWorker, PDFWorker,
PermissionFlag, PermissionFlag,
PixelsPerInch, PixelsPerInch,
PromiseCapability,
RenderingCancelledException, RenderingCancelledException,
renderTextLayer, renderTextLayer,
setLayerDimensions, setLayerDimensions,