refactor: change target promises to be deferred (#10191)

This commit is contained in:
Alex Rudenko 2023-05-16 17:18:22 +02:00 committed by GitHub
parent 354ac3bfc8
commit 5a5e4d46a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 41 deletions

View File

@ -39,7 +39,13 @@ import {ChromeTargetManager} from './ChromeTargetManager.js';
import {CDPSession, Connection, ConnectionEmittedEvents} from './Connection.js'; import {CDPSession, Connection, ConnectionEmittedEvents} from './Connection.js';
import {FirefoxTargetManager} from './FirefoxTargetManager.js'; import {FirefoxTargetManager} from './FirefoxTargetManager.js';
import {Viewport} from './PuppeteerViewport.js'; import {Viewport} from './PuppeteerViewport.js';
import {OtherTarget, PageTarget, Target, WorkerTarget} from './Target.js'; import {
InitializationStatus,
OtherTarget,
PageTarget,
Target,
WorkerTarget,
} from './Target.js';
import {TargetManager, TargetManagerEmittedEvents} from './TargetManager.js'; import {TargetManager, TargetManagerEmittedEvents} from './TargetManager.js';
import {TaskQueue} from './TaskQueue.js'; import {TaskQueue} from './TaskQueue.js';
import {waitWithTimeout} from './util.js'; import {waitWithTimeout} from './util.js';
@ -364,8 +370,8 @@ export class CDPBrowser extends BrowserBase {
}; };
#onDetachedFromTarget = async (target: Target): Promise<void> => { #onDetachedFromTarget = async (target: Target): Promise<void> => {
target._initializedCallback(false); target._initializedPromise.resolve(InitializationStatus.ABORTED);
target._closedCallback(); target._isClosedPromise.resolve();
if (await target._initializedPromise) { if (await target._initializedPromise) {
this.emit(BrowserEmittedEvents.TargetDestroyed, target); this.emit(BrowserEmittedEvents.TargetDestroyed, target);
target target
@ -447,7 +453,7 @@ export class CDPBrowser extends BrowserBase {
return Array.from( return Array.from(
this.#targetManager.getAvailableTargets().values() this.#targetManager.getAvailableTargets().values()
).filter(target => { ).filter(target => {
return target._isInitialized; return target._initializedPromise.resolved();
}); });
} }

View File

@ -22,7 +22,7 @@ import {createDeferredPromise} from '../util/DeferredPromise.js';
import {CDPSession, Connection} from './Connection.js'; import {CDPSession, Connection} from './Connection.js';
import {EventEmitter} from './EventEmitter.js'; import {EventEmitter} from './EventEmitter.js';
import {Target} from './Target.js'; import {InitializationStatus, Target} from './Target.js';
import { import {
TargetInterceptor, TargetInterceptor,
TargetFactory, TargetFactory,
@ -267,7 +267,8 @@ export class ChromeTargetManager extends EventEmitter implements TargetManager {
return; return;
} }
const previousURL = target.url(); const previousURL = target.url();
const wasInitialized = target._isInitialized; const wasInitialized =
target._initializedPromise.value() === InitializationStatus.SUCCESS;
target._targetInfoChanged(event.targetInfo); target._targetInfoChanged(event.targetInfo);

View File

@ -19,6 +19,7 @@ import {Protocol} from 'devtools-protocol';
import type {Browser} from '../api/Browser.js'; import type {Browser} from '../api/Browser.js';
import type {BrowserContext} from '../api/BrowserContext.js'; import type {BrowserContext} from '../api/BrowserContext.js';
import {Page, PageEmittedEvents} from '../api/Page.js'; import {Page, PageEmittedEvents} from '../api/Page.js';
import {createDeferredPromise} from '../util/DeferredPromise.js';
import {CDPSession} from './Connection.js'; import {CDPSession} from './Connection.js';
import {CDPPage} from './Page.js'; import {CDPPage} from './Page.js';
@ -28,6 +29,14 @@ import {TaskQueue} from './TaskQueue.js';
import {debugError} from './util.js'; import {debugError} from './util.js';
import {WebWorker} from './WebWorker.js'; import {WebWorker} from './WebWorker.js';
/**
* @internal
*/
export enum InitializationStatus {
SUCCESS = 'success',
ABORTED = 'aborted',
}
/** /**
* Target represents a * Target represents a
* {@link https://chromedevtools.github.io/devtools-protocol/tot/Target/ | CDP target}. * {@link https://chromedevtools.github.io/devtools-protocol/tot/Target/ | CDP target}.
@ -40,35 +49,22 @@ export class Target {
#browserContext: BrowserContext; #browserContext: BrowserContext;
#session?: CDPSession; #session?: CDPSession;
#targetInfo: Protocol.Target.TargetInfo; #targetInfo: Protocol.Target.TargetInfo;
#targetManager: TargetManager;
#sessionFactory: (isAutoAttachEmulated: boolean) => Promise<CDPSession>; #sessionFactory: (isAutoAttachEmulated: boolean) => Promise<CDPSession>;
/** /**
* @internal * @internal
*/ */
_initializedPromise: Promise<boolean>; _initializedPromise = createDeferredPromise<InitializationStatus>();
/** /**
* @internal * @internal
*/ */
_initializedCallback!: (x: boolean) => void; _isClosedPromise = createDeferredPromise<void>();
/**
* @internal
*/
_isClosedPromise: Promise<void>;
/**
* @internal
*/
_closedCallback!: () => void;
/**
* @internal
*/
_isInitialized = false;
/** /**
* @internal * @internal
*/ */
_targetId: string; _targetId: string;
#targetManager: TargetManager;
/** /**
* @internal * @internal
*/ */
@ -85,12 +81,6 @@ export class Target {
this.#browserContext = browserContext; this.#browserContext = browserContext;
this._targetId = targetInfo.targetId; this._targetId = targetInfo.targetId;
this.#sessionFactory = sessionFactory; this.#sessionFactory = sessionFactory;
this._initializedPromise = new Promise<boolean>(fulfill => {
return (this._initializedCallback = fulfill);
});
this._isClosedPromise = new Promise<void>(fulfill => {
return (this._closedCallback = fulfill);
});
this._initialize(); this._initialize();
} }
@ -208,21 +198,15 @@ export class Target {
* @internal * @internal
*/ */
protected _initialize(): void { protected _initialize(): void {
// TODO: refactor to deferred promises. this._initializedPromise.resolve(InitializationStatus.SUCCESS);
this._isInitialized = true;
if (this._isInitialized) {
this._initializedCallback(true);
}
} }
/** /**
* @internal * @internal
*/ */
protected _checkIfInitialized(): void { protected _checkIfInitialized(): void {
if (!this._isInitialized) { if (!this._initializedPromise.resolved()) {
this._isInitialized = true; this._initializedPromise.resolve(InitializationStatus.SUCCESS);
this._initializedCallback(true);
return;
} }
} }
@ -309,12 +293,11 @@ export class PageTarget extends Target {
} }
override _checkIfInitialized(): void { override _checkIfInitialized(): void {
if (this._isInitialized) { if (this._initializedPromise.resolved()) {
return; return;
} }
this._isInitialized = this._getTargetInfo().url !== ''; if (this._getTargetInfo().url !== '') {
if (this._isInitialized) { this._initializedPromise.resolve(InitializationStatus.SUCCESS);
this._initializedCallback(true);
} }
} }
} }

View File

@ -8,6 +8,7 @@ export interface DeferredPromise<T> extends Promise<T> {
resolved: () => boolean; resolved: () => boolean;
resolve: (value: T) => void; resolve: (value: T) => void;
reject: (reason?: unknown) => void; reject: (reason?: unknown) => void;
value: () => T | undefined;
} }
/** /**
@ -32,6 +33,7 @@ export function createDeferredPromise<T>(
): DeferredPromise<T> { ): DeferredPromise<T> {
let isResolved = false; let isResolved = false;
let isRejected = false; let isRejected = false;
let _value: T | undefined;
let resolver: (value: T) => void; let resolver: (value: T) => void;
let rejector: (reason?: unknown) => void; let rejector: (reason?: unknown) => void;
const taskPromise = new Promise<T>((resolve, reject) => { const taskPromise = new Promise<T>((resolve, reject) => {
@ -57,6 +59,7 @@ export function createDeferredPromise<T>(
clearTimeout(timeoutId); clearTimeout(timeoutId);
} }
isResolved = true; isResolved = true;
_value = value;
resolver(value); resolver(value);
}, },
reject: (err?: unknown) => { reject: (err?: unknown) => {
@ -64,5 +67,8 @@ export function createDeferredPromise<T>(
isRejected = true; isRejected = true;
rejector(err); rejector(err);
}, },
value: () => {
return _value;
},
}); });
} }