refactor: Deferred to a class (#10282)
This commit is contained in:
parent
5fc136eec1
commit
39e9737232
@ -194,6 +194,12 @@ module.exports = {
|
||||
selector: "CallExpression[callee.name='require']",
|
||||
message: '`require` statements are not allowed. Use `import`.',
|
||||
},
|
||||
{
|
||||
// We need this as NodeJS will run until all the timers have resolved
|
||||
message: 'Use method `Deferred.race()` instead.',
|
||||
selector:
|
||||
'MemberExpression[object.name="Promise"][property.name="race"]',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-floating-promises': [
|
||||
'error',
|
||||
|
@ -61,7 +61,6 @@ import {
|
||||
import type {WebWorker} from '../common/WebWorker.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
|
||||
import type {Browser} from './Browser.js';
|
||||
import type {BrowserContext} from './BrowserContext.js';
|
||||
@ -1638,8 +1637,8 @@ export class Page extends EventEmitter {
|
||||
timeout: number,
|
||||
closedDeferred: Deferred<TargetCloseError>
|
||||
): Promise<void> {
|
||||
const idleDeferred = createDeferred<void>();
|
||||
const abortDeferred = createDeferred<Error>();
|
||||
const idleDeferred = Deferred.create<void>();
|
||||
const abortDeferred = Deferred.create<Error>();
|
||||
|
||||
let idleTimer: NodeJS.Timeout | undefined;
|
||||
const cleanup = () => {
|
||||
@ -1651,7 +1650,9 @@ export class Page extends EventEmitter {
|
||||
clearTimeout(idleTimer);
|
||||
|
||||
if (networkManager.inFlightRequestsCount() === 0) {
|
||||
idleTimer = setTimeout(idleDeferred.resolve, idleTime);
|
||||
idleTimer = setTimeout(() => {
|
||||
return idleDeferred.resolve();
|
||||
}, idleTime);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1676,11 +1677,7 @@ export class Page extends EventEmitter {
|
||||
|
||||
evaluate();
|
||||
|
||||
await Promise.race([
|
||||
idleDeferred.valueOrThrow(),
|
||||
...eventPromises,
|
||||
closedDeferred.valueOrThrow(),
|
||||
]).then(
|
||||
await Deferred.race([idleDeferred, ...eventPromises, closedDeferred]).then(
|
||||
r => {
|
||||
cleanup();
|
||||
return r;
|
||||
|
@ -33,7 +33,7 @@ import {
|
||||
import {BrowserContext} from '../api/BrowserContext.js';
|
||||
import {Page} from '../api/Page.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {ChromeTargetManager} from './ChromeTargetManager.js';
|
||||
import {CDPSession, Connection, ConnectionEmittedEvents} from './Connection.js';
|
||||
@ -501,7 +501,7 @@ export class CDPBrowser extends BrowserBase {
|
||||
options: WaitForTargetOptions = {}
|
||||
): Promise<Target> {
|
||||
const {timeout = 30000} = options;
|
||||
const targetDeferred = createDeferred<Target | PromiseLike<Target>>();
|
||||
const targetDeferred = Deferred.create<Target | PromiseLike<Target>>();
|
||||
|
||||
this.on(BrowserEmittedEvents.TargetCreated, check);
|
||||
this.on(BrowserEmittedEvents.TargetChanged, check);
|
||||
|
@ -18,7 +18,7 @@ import {Protocol} from 'devtools-protocol';
|
||||
|
||||
import {TargetFilterCallback} from '../api/Browser.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSession, Connection} from './Connection.js';
|
||||
import {EventEmitter} from './EventEmitter.js';
|
||||
@ -81,7 +81,7 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
|
||||
(event: Protocol.Target.DetachedFromTargetEvent) => void
|
||||
> = new WeakMap();
|
||||
|
||||
#initializeDeferred = createDeferred<void>();
|
||||
#initializeDeferred = Deferred.create<void>();
|
||||
#targetsIdsForInit: Set<string> = new Set();
|
||||
|
||||
constructor(
|
||||
|
@ -18,7 +18,7 @@ import {Protocol} from 'devtools-protocol';
|
||||
import {ProtocolMapping} from 'devtools-protocol/types/protocol-mapping.js';
|
||||
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred, Deferred} from '../util/util.js';
|
||||
import {Deferred} from '../util/util.js';
|
||||
|
||||
import {ConnectionTransport} from './ConnectionTransport.js';
|
||||
import {debug} from './Debug.js';
|
||||
@ -64,7 +64,7 @@ function createIncrementalIdGenerator(): GetIdFn {
|
||||
export class Callback {
|
||||
#id: number;
|
||||
#error = new ProtocolError();
|
||||
#deferred = createDeferred<unknown>();
|
||||
#deferred = Deferred.create<unknown>();
|
||||
#timer?: ReturnType<typeof setTimeout>;
|
||||
#label: string;
|
||||
|
||||
|
@ -18,7 +18,7 @@ import Protocol from 'devtools-protocol';
|
||||
|
||||
import {WaitTimeoutOptions} from '../api/Page.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred, Deferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSession} from './Connection.js';
|
||||
import {TimeoutSettings} from './TimeoutSettings.js';
|
||||
@ -151,7 +151,7 @@ export class DeviceRequestPrompt {
|
||||
}
|
||||
|
||||
const {timeout = this.#timeoutSettings.timeout()} = options;
|
||||
const deferred = createDeferred<DeviceRequestPromptDevice>({
|
||||
const deferred = Deferred.create<DeviceRequestPromptDevice>({
|
||||
message: `Waiting for \`DeviceRequestPromptDevice\` failed: ${timeout}ms exceeded`,
|
||||
timeout,
|
||||
});
|
||||
@ -250,7 +250,7 @@ export class DeviceRequestPromptManager {
|
||||
}
|
||||
|
||||
const {timeout = this.#timeoutSettings.timeout()} = options;
|
||||
const deferred = createDeferred<DeviceRequestPrompt>({
|
||||
const deferred = Deferred.create<DeviceRequestPrompt>({
|
||||
message: `Waiting for \`DeviceRequestPrompt\` failed: ${timeout}ms exceeded`,
|
||||
timeout,
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ import {Protocol} from 'devtools-protocol';
|
||||
|
||||
import {TargetFilterCallback} from '../api/Browser.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSession, Connection} from './Connection.js';
|
||||
import {EventEmitter} from './EventEmitter.js';
|
||||
@ -88,7 +88,7 @@ export class FirefoxTargetManager
|
||||
(event: Protocol.Target.AttachedToTargetEvent) => Promise<void>
|
||||
> = new WeakMap();
|
||||
|
||||
#initializeDeferred = createDeferred<void>();
|
||||
#initializeDeferred = Deferred.create<void>();
|
||||
#targetsIdsForInit: Set<string> = new Set();
|
||||
|
||||
constructor(
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
import {HTTPResponse} from '../api/HTTPResponse.js';
|
||||
import {Page, WaitTimeoutOptions} from '../api/Page.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
import {isErrorLike} from '../util/ErrorLike.js';
|
||||
|
||||
import {CDPSession} from './Connection.js';
|
||||
@ -123,7 +124,7 @@ export class Frame extends BaseFrame {
|
||||
waitUntil,
|
||||
timeout
|
||||
);
|
||||
let error = await Promise.race([
|
||||
let error = await Deferred.race([
|
||||
navigate(
|
||||
this.#client,
|
||||
url,
|
||||
@ -134,7 +135,7 @@ export class Frame extends BaseFrame {
|
||||
watcher.timeoutOrTerminationPromise(),
|
||||
]);
|
||||
if (!error) {
|
||||
error = await Promise.race([
|
||||
error = await Deferred.race([
|
||||
watcher.timeoutOrTerminationPromise(),
|
||||
ensureNewDocumentNavigation
|
||||
? watcher.newDocumentNavigationPromise()
|
||||
@ -197,7 +198,7 @@ export class Frame extends BaseFrame {
|
||||
waitUntil,
|
||||
timeout
|
||||
);
|
||||
const error = await Promise.race([
|
||||
const error = await Deferred.race([
|
||||
watcher.timeoutOrTerminationPromise(),
|
||||
watcher.sameDocumentNavigationPromise(),
|
||||
watcher.newDocumentNavigationPromise(),
|
||||
@ -389,8 +390,8 @@ export class Frame extends BaseFrame {
|
||||
|
||||
return this.worlds[MAIN_WORLD].transferHandle(
|
||||
await this.worlds[PUPPETEER_WORLD].evaluateHandle(
|
||||
async ({createDeferred}, {url, id, type, content}) => {
|
||||
const deferred = createDeferred<void>();
|
||||
async ({Deferred}, {url, id, type, content}) => {
|
||||
const deferred = Deferred.create<void>();
|
||||
const script = document.createElement('script');
|
||||
script.type = type;
|
||||
script.text = content;
|
||||
@ -457,8 +458,8 @@ export class Frame extends BaseFrame {
|
||||
|
||||
return this.worlds[MAIN_WORLD].transferHandle(
|
||||
await this.worlds[PUPPETEER_WORLD].evaluateHandle(
|
||||
async ({createDeferred}, {url, content}) => {
|
||||
const deferred = createDeferred<void>();
|
||||
async ({Deferred}, {url, content}) => {
|
||||
const deferred = Deferred.create<void>();
|
||||
let element: HTMLStyleElement | HTMLLinkElement;
|
||||
if (!url) {
|
||||
element = document.createElement('style');
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import {Frame as BaseFrame} from '../api/Frame.js';
|
||||
import {createDeferred, Deferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
/**
|
||||
* Keeps track of the page frame tree and it's is managed by
|
||||
@ -50,7 +50,7 @@ export class FrameTree<Frame extends BaseFrame> {
|
||||
if (frame) {
|
||||
return Promise.resolve(frame);
|
||||
}
|
||||
const deferred = createDeferred<Frame>();
|
||||
const deferred = Deferred.create<Frame>();
|
||||
const callbacks =
|
||||
this.#waitRequests.get(frameId) || new Set<Deferred<Frame>>();
|
||||
callbacks.add(deferred);
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
HTTPResponse as BaseHTTPResponse,
|
||||
RemoteAddress,
|
||||
} from '../api/HTTPResponse.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSession} from './Connection.js';
|
||||
import {ProtocolError} from './Errors.js';
|
||||
@ -34,7 +34,7 @@ export class HTTPResponse extends BaseHTTPResponse {
|
||||
#client: CDPSession;
|
||||
#request: HTTPRequest;
|
||||
#contentPromise: Promise<Buffer> | null = null;
|
||||
#bodyLoadedDeferred = createDeferred<Error | void>();
|
||||
#bodyLoadedDeferred = Deferred.create<Error | void>();
|
||||
#remoteAddress: RemoteAddress;
|
||||
#status: number;
|
||||
#statusText: string;
|
||||
|
@ -19,7 +19,7 @@ import {Protocol} from 'devtools-protocol';
|
||||
import type {ClickOptions, ElementHandle} from '../api/ElementHandle.js';
|
||||
import {JSHandle} from '../api/JSHandle.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {Binding} from './Binding.js';
|
||||
import {CDPSession} from './Connection.js';
|
||||
@ -101,7 +101,7 @@ export interface IsolatedWorldChart {
|
||||
export class IsolatedWorld {
|
||||
#frame: Frame;
|
||||
#document?: ElementHandle<Document>;
|
||||
#context = createDeferred<ExecutionContext>();
|
||||
#context = Deferred.create<ExecutionContext>();
|
||||
#detached = false;
|
||||
|
||||
// Set of bindings that have been registered in the current context.
|
||||
@ -144,7 +144,7 @@ export class IsolatedWorld {
|
||||
|
||||
clearContext(): void {
|
||||
this.#document = undefined;
|
||||
this.#context = createDeferred();
|
||||
this.#context = Deferred.create();
|
||||
}
|
||||
|
||||
setContext(context: ExecutionContext): void {
|
||||
@ -304,7 +304,7 @@ export class IsolatedWorld {
|
||||
waitUntil,
|
||||
timeout
|
||||
);
|
||||
const error = await Promise.race([
|
||||
const error = await Deferred.race<void | Error | undefined>([
|
||||
watcher.timeoutOrTerminationPromise(),
|
||||
watcher.lifecyclePromise(),
|
||||
]);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import {HTTPResponse} from '../api/HTTPResponse.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {Deferred, createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSessionEmittedEvents} from './Connection.js';
|
||||
import {TimeoutError} from './Errors.js';
|
||||
@ -71,10 +71,10 @@ export class LifecycleWatcher {
|
||||
#eventListeners: PuppeteerEventListener[];
|
||||
#initialLoaderId: string;
|
||||
|
||||
#sameDocumentNavigationDeferred = createDeferred<Error | undefined>();
|
||||
#lifecycleDeferred = createDeferred<void>();
|
||||
#newDocumentNavigationDeferred = createDeferred<Error | undefined>();
|
||||
#terminationDeferred = createDeferred<Error | undefined>();
|
||||
#sameDocumentNavigationDeferred = Deferred.create<undefined>();
|
||||
#lifecycleDeferred = Deferred.create<void>();
|
||||
#newDocumentNavigationDeferred = Deferred.create<undefined>();
|
||||
#terminationDeferred = Deferred.create<Error>();
|
||||
|
||||
#timeoutPromise: Promise<TimeoutError | undefined>;
|
||||
|
||||
@ -169,7 +169,7 @@ export class LifecycleWatcher {
|
||||
// navigation requests reported by the backend. This generally should not
|
||||
// happen by it looks like it's possible.
|
||||
this.#navigationResponseReceived?.resolve();
|
||||
this.#navigationResponseReceived = createDeferred();
|
||||
this.#navigationResponseReceived = Deferred.create();
|
||||
if (request.response() !== null) {
|
||||
this.#navigationResponseReceived?.resolve();
|
||||
}
|
||||
@ -222,10 +222,7 @@ export class LifecycleWatcher {
|
||||
}
|
||||
|
||||
timeoutOrTerminationPromise(): Promise<Error | TimeoutError | undefined> {
|
||||
return Promise.race([
|
||||
this.#timeoutPromise,
|
||||
this.#terminationDeferred.valueOrThrow(),
|
||||
]);
|
||||
return Deferred.race([this.#timeoutPromise, this.#terminationDeferred]);
|
||||
}
|
||||
|
||||
async #createTimeoutPromise(): Promise<TimeoutError | undefined> {
|
||||
@ -299,6 +296,6 @@ export class LifecycleWatcher {
|
||||
|
||||
dispose(): void {
|
||||
removeEventListeners(this.#eventListeners);
|
||||
this.#maximumTimer !== undefined && clearTimeout(this.#maximumTimer);
|
||||
clearTimeout(this.#maximumTimer);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ import {
|
||||
NewDocumentScriptEvaluation,
|
||||
} from '../api/Page.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred, Deferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
import {isErrorLike} from '../util/ErrorLike.js';
|
||||
|
||||
import {Accessibility} from './Accessibility.js';
|
||||
@ -153,7 +153,7 @@ export class CDPPage extends Page {
|
||||
#screenshotTaskQueue: TaskQueue;
|
||||
#workers = new Map<string, WebWorker>();
|
||||
#fileChooserDeferreds = new Set<Deferred<FileChooser>>();
|
||||
#sessionCloseDeferred = createDeferred<TargetCloseError>();
|
||||
#sessionCloseDeferred = Deferred.create<TargetCloseError>();
|
||||
#serviceWorkerBypassed = false;
|
||||
#userDragInterceptionEnabled = false;
|
||||
|
||||
@ -374,7 +374,7 @@ export class CDPPage extends Page {
|
||||
): Promise<FileChooser> {
|
||||
const needsEnable = this.#fileChooserDeferreds.size === 0;
|
||||
const {timeout = this.#timeoutSettings.timeout()} = options;
|
||||
const deferred = createDeferred<FileChooser>({
|
||||
const deferred = Deferred.create<FileChooser>({
|
||||
message: `Waiting for \`FileChooser\` failed: ${timeout}ms exceeded`,
|
||||
timeout,
|
||||
});
|
||||
@ -1029,7 +1029,7 @@ export class CDPPage extends Page {
|
||||
};
|
||||
}
|
||||
|
||||
const eventRace: Promise<Frame> = Promise.race([
|
||||
const eventRace: Promise<Frame> = Deferred.race([
|
||||
waitForEvent(
|
||||
this.#frameManager,
|
||||
FrameManagerEmittedEvents.FrameAttached,
|
||||
|
@ -19,7 +19,7 @@ import {Protocol} from 'devtools-protocol';
|
||||
import type {Browser} from '../api/Browser.js';
|
||||
import type {BrowserContext} from '../api/BrowserContext.js';
|
||||
import {Page, PageEmittedEvents} from '../api/Page.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSession} from './Connection.js';
|
||||
import {CDPPage} from './Page.js';
|
||||
@ -55,11 +55,11 @@ export class Target {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_initializedDeferred = createDeferred<InitializationStatus>();
|
||||
_initializedDeferred = Deferred.create<InitializationStatus>();
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_isClosedDeferred = createDeferred<void>();
|
||||
_isClosedDeferred = Deferred.create<void>();
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -17,7 +17,7 @@
|
||||
import {ElementHandle} from '../api/ElementHandle.js';
|
||||
import {JSHandle} from '../api/JSHandle.js';
|
||||
import type {Poller} from '../injected/Poller.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
import {isErrorLike} from '../util/ErrorLike.js';
|
||||
import {stringifyFunction} from '../util/Function.js';
|
||||
|
||||
@ -49,7 +49,7 @@ export class WaitTask<T = unknown> {
|
||||
|
||||
#timeout?: NodeJS.Timeout;
|
||||
|
||||
#result = createDeferred<HandleFor<T>>();
|
||||
#result = Deferred.create<HandleFor<T>>();
|
||||
|
||||
#poller?: JSHandle<Poller<T>>;
|
||||
#signal?: AbortSignal;
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
import {Protocol} from 'devtools-protocol';
|
||||
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
import {CDPSession} from './Connection.js';
|
||||
import {ConsoleMessageType} from './ConsoleMessage.js';
|
||||
@ -68,7 +68,7 @@ export type ExceptionThrownCallback = (
|
||||
* @public
|
||||
*/
|
||||
export class WebWorker extends EventEmitter {
|
||||
#executionContext = createDeferred<ExecutionContext>();
|
||||
#executionContext = Deferred.create<ExecutionContext>();
|
||||
|
||||
#client: CDPSession;
|
||||
#url: string;
|
||||
|
@ -25,7 +25,7 @@ import {
|
||||
WaitForOptions,
|
||||
} from '../../api/Page.js';
|
||||
import {assert} from '../../util/assert.js';
|
||||
import {createDeferred} from '../../util/Deferred.js';
|
||||
import {Deferred} from '../../util/Deferred.js';
|
||||
import {ConsoleMessage, ConsoleMessageLocation} from '../ConsoleMessage.js';
|
||||
import {TargetCloseError} from '../Errors.js';
|
||||
import {Handler} from '../EventEmitter.js';
|
||||
@ -61,7 +61,7 @@ export class Page extends PageBase {
|
||||
#frameTree = new FrameTree<Frame>();
|
||||
#networkManager: NetworkManager;
|
||||
#viewport: Viewport | null = null;
|
||||
#closedDeferred = createDeferred<TargetCloseError>();
|
||||
#closedDeferred = Deferred.create<TargetCloseError>();
|
||||
#subscribedEvents = new Map<string, Handler<any>>([
|
||||
['log.entryAdded', this.#onLogEntryAdded.bind(this)],
|
||||
[
|
||||
|
@ -22,8 +22,8 @@ import type {ElementHandle} from '../api/ElementHandle.js';
|
||||
import type {JSHandle} from '../api/JSHandle.js';
|
||||
import {Page} from '../api/Page.js';
|
||||
import {isNode} from '../environment.js';
|
||||
import {Deferred} from '../puppeteer-core.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {isErrorLike} from '../util/ErrorLike.js';
|
||||
|
||||
import type {CDPSession} from './Connection.js';
|
||||
@ -382,7 +382,7 @@ export async function waitForEvent<T>(
|
||||
timeout: number,
|
||||
abortPromise: Promise<Error>
|
||||
): Promise<T> {
|
||||
const deferred = createDeferred<T>({
|
||||
const deferred = Deferred.create<T>({
|
||||
message: `Timeout exceeded while waiting for event ${String(eventName)}`,
|
||||
timeout,
|
||||
});
|
||||
@ -391,23 +391,19 @@ export async function waitForEvent<T>(
|
||||
deferred.resolve(event);
|
||||
}
|
||||
});
|
||||
return Promise.race([deferred.valueOrThrow(), abortPromise])
|
||||
.then(
|
||||
r => {
|
||||
removeEventListeners([listener]);
|
||||
if (isErrorLike(r)) {
|
||||
throw r;
|
||||
}
|
||||
return r;
|
||||
},
|
||||
error => {
|
||||
removeEventListeners([listener]);
|
||||
throw error;
|
||||
return Deferred.race<T | Error>([deferred, abortPromise]).then(
|
||||
r => {
|
||||
removeEventListeners([listener]);
|
||||
if (isErrorLike(r)) {
|
||||
throw r;
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
deferred.reject(new Error('Cleared'));
|
||||
});
|
||||
return r;
|
||||
},
|
||||
error => {
|
||||
removeEventListeners([listener]);
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -509,12 +505,12 @@ export async function waitWithTimeout<T>(
|
||||
taskName: string,
|
||||
timeout: number
|
||||
): Promise<T> {
|
||||
const deferred = createDeferred<never>({
|
||||
const deferred = Deferred.create<never>({
|
||||
message: `waiting for ${taskName} failed: timeout ${timeout}ms exceeded`,
|
||||
timeout,
|
||||
});
|
||||
|
||||
return await Promise.race([promise, deferred.valueOrThrow()]).finally(() => {
|
||||
return await Deferred.race([promise, deferred.valueOrThrow()]).finally(() => {
|
||||
deferred.reject(new Error('Cleared'));
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import {assert} from '../util/assert.js';
|
||||
import {createDeferred, Deferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -42,7 +42,7 @@ export class MutationPoller<T> implements Poller<T> {
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
const deferred = (this.#deferred = createDeferred<T>());
|
||||
const deferred = (this.#deferred = Deferred.create<T>());
|
||||
const result = await this.#fn();
|
||||
if (result) {
|
||||
deferred.resolve(result);
|
||||
@ -92,7 +92,7 @@ export class RAFPoller<T> implements Poller<T> {
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
const deferred = (this.#deferred = createDeferred<T>());
|
||||
const deferred = (this.#deferred = Deferred.create<T>());
|
||||
const result = await this.#fn();
|
||||
if (result) {
|
||||
deferred.resolve(result);
|
||||
@ -143,7 +143,7 @@ export class IntervalPoller<T> implements Poller<T> {
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
const deferred = (this.#deferred = createDeferred<T>());
|
||||
const deferred = (this.#deferred = Deferred.create<T>());
|
||||
const result = await this.#fn();
|
||||
if (result) {
|
||||
deferred.resolve(result);
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {createDeferred} from '../util/Deferred.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
import {createFunction} from '../util/Function.js';
|
||||
|
||||
import * as ARIAQuerySelector from './ARIAQuerySelector.js';
|
||||
@ -41,7 +41,7 @@ const PuppeteerUtil = Object.freeze({
|
||||
...TextQuerySelector,
|
||||
...util,
|
||||
...XPathQuerySelector,
|
||||
createDeferred,
|
||||
Deferred,
|
||||
createFunction,
|
||||
createTextContent,
|
||||
IntervalPoller,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {DEFERRED_PROMISE_DEBUG_TIMEOUT} from '../environment.js';
|
||||
|
||||
import {Deferred, createDeferred} from './Deferred.js';
|
||||
import {Deferred} from './Deferred.js';
|
||||
|
||||
/**
|
||||
* Creates and returns a deferred promise using DEFERRED_PROMISE_DEBUG_TIMEOUT
|
||||
@ -10,10 +10,10 @@ import {Deferred, createDeferred} from './Deferred.js';
|
||||
*/
|
||||
export function createDebuggableDeferred<T>(message: string): Deferred<T> {
|
||||
if (DEFERRED_PROMISE_DEBUG_TIMEOUT > 0) {
|
||||
return createDeferred({
|
||||
return Deferred.create({
|
||||
message,
|
||||
timeout: DEFERRED_PROMISE_DEBUG_TIMEOUT,
|
||||
});
|
||||
}
|
||||
return createDeferred();
|
||||
return Deferred.create();
|
||||
}
|
||||
|
@ -1,17 +1,5 @@
|
||||
import {TimeoutError} from '../common/Errors.js';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface Deferred<T> {
|
||||
finished: () => boolean;
|
||||
resolved: () => boolean;
|
||||
resolve: (value: T) => void;
|
||||
reject: (error: Error) => void;
|
||||
value: () => T | Error | undefined;
|
||||
valueOrThrow: () => Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@ -29,61 +17,94 @@ export interface DeferredOptions {
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function createDeferred<T>(opts?: DeferredOptions): Deferred<T> {
|
||||
let isResolved = false;
|
||||
let isRejected = false;
|
||||
let _value: T | Error | undefined;
|
||||
let resolver: (value: void) => void;
|
||||
const taskPromise = new Promise<void>(resolve => {
|
||||
resolver = resolve;
|
||||
export class Deferred<T> {
|
||||
#isResolved = false;
|
||||
#isRejected = false;
|
||||
#value: T | Error | undefined;
|
||||
#resolver: (value: void) => void = () => {};
|
||||
#taskPromise = new Promise<void>(resolve => {
|
||||
this.#resolver = resolve;
|
||||
});
|
||||
const timeoutId =
|
||||
opts && opts.timeout > 0
|
||||
? setTimeout(() => {
|
||||
reject(new TimeoutError(opts.message));
|
||||
}, opts.timeout)
|
||||
: undefined;
|
||||
#timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
function finish(value: T | Error) {
|
||||
clearTimeout(timeoutId);
|
||||
_value = value;
|
||||
resolver();
|
||||
constructor(opts?: DeferredOptions) {
|
||||
this.#timeoutId =
|
||||
opts && opts.timeout > 0
|
||||
? setTimeout(() => {
|
||||
this.reject(new TimeoutError(opts.message));
|
||||
}, opts.timeout)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function resolve(value: T) {
|
||||
if (isRejected || isResolved) {
|
||||
#finish(value: T | Error) {
|
||||
clearTimeout(this.#timeoutId);
|
||||
this.#value = value;
|
||||
this.#resolver();
|
||||
}
|
||||
|
||||
resolve(value: T): void {
|
||||
if (this.#isRejected || this.#isResolved) {
|
||||
return;
|
||||
}
|
||||
isResolved = true;
|
||||
finish(value);
|
||||
this.#isResolved = true;
|
||||
this.#finish(value);
|
||||
}
|
||||
|
||||
function reject(error: Error) {
|
||||
if (isRejected || isResolved) {
|
||||
reject(error: Error): void {
|
||||
if (this.#isRejected || this.#isResolved) {
|
||||
return;
|
||||
}
|
||||
isRejected = true;
|
||||
finish(error);
|
||||
this.#isRejected = true;
|
||||
this.#finish(error);
|
||||
}
|
||||
|
||||
return {
|
||||
resolved: () => {
|
||||
return isResolved;
|
||||
},
|
||||
finished: () => {
|
||||
return isResolved || isRejected;
|
||||
},
|
||||
resolve,
|
||||
reject,
|
||||
value: () => {
|
||||
return _value;
|
||||
},
|
||||
async valueOrThrow() {
|
||||
await taskPromise;
|
||||
if (isRejected) {
|
||||
throw _value;
|
||||
resolved(): boolean {
|
||||
return this.#isResolved;
|
||||
}
|
||||
|
||||
finished(): boolean {
|
||||
return this.#isResolved || this.#isRejected;
|
||||
}
|
||||
|
||||
value(): T | Error | undefined {
|
||||
return this.#value;
|
||||
}
|
||||
|
||||
async valueOrThrow(): Promise<T> {
|
||||
await this.#taskPromise;
|
||||
if (this.#isRejected) {
|
||||
throw this.#value;
|
||||
}
|
||||
return this.#value as T;
|
||||
}
|
||||
|
||||
static create<R>(opts?: DeferredOptions): Deferred<R> {
|
||||
return new Deferred<R>(opts);
|
||||
}
|
||||
|
||||
static async race<R>(
|
||||
awaitables: Array<Promise<R> | Deferred<R>>
|
||||
): Promise<R> {
|
||||
const deferredWithTimeout: Set<Deferred<R>> = new Set();
|
||||
try {
|
||||
const promises = awaitables.map(value => {
|
||||
if (value instanceof Deferred) {
|
||||
deferredWithTimeout.add(value);
|
||||
|
||||
return value.valueOrThrow();
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
return await Promise.race(promises);
|
||||
} finally {
|
||||
for (const deferred of deferredWithTimeout) {
|
||||
// We need to stop the timeout else
|
||||
// Node.JS will keep running the event loop till the
|
||||
// timer executes
|
||||
deferred.reject(new Error('Timeout cleared'));
|
||||
}
|
||||
return _value as T;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,7 @@
|
||||
*/
|
||||
|
||||
import expect from 'expect';
|
||||
import {
|
||||
Deferred,
|
||||
createDeferred,
|
||||
} from 'puppeteer-core/internal/util/Deferred.js';
|
||||
import {Deferred} from 'puppeteer-core/internal/util/Deferred.js';
|
||||
|
||||
describe('DeferredPromise', function () {
|
||||
it('should catch errors', async () => {
|
||||
@ -30,7 +27,7 @@ describe('DeferredPromise', function () {
|
||||
}
|
||||
// Async function that fails.
|
||||
function fails(): Deferred<void> {
|
||||
const deferred = createDeferred<void>();
|
||||
const deferred = Deferred.create<void>();
|
||||
setTimeout(() => {
|
||||
deferred.reject(new Error('test'));
|
||||
}, 25);
|
||||
|
Loading…
Reference in New Issue
Block a user