refactor: move execution context events (#12402)

This commit is contained in:
Alex Rudenko 2024-05-07 09:50:56 +02:00 committed by GitHub
parent dfa999da0f
commit 0eae3d1bb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 45 deletions

View File

@ -6,7 +6,7 @@
import type {Protocol} from 'devtools-protocol'; import type {Protocol} from 'devtools-protocol';
import type {CDPSession, CDPSessionEvents} from '../api/CDPSession.js'; import type {CDPSession} from '../api/CDPSession.js';
import type {ElementHandle} from '../api/ElementHandle.js'; import type {ElementHandle} from '../api/ElementHandle.js';
import type {JSHandle} from '../api/JSHandle.js'; import type {JSHandle} from '../api/JSHandle.js';
import {EventEmitter} from '../common/EventEmitter.js'; import {EventEmitter} from '../common/EventEmitter.js';
@ -62,31 +62,42 @@ const ariaQuerySelectorAllBinding = new Binding(
/** /**
* @internal * @internal
*/ */
export class ExecutionContext implements Disposable { export class ExecutionContext
extends EventEmitter<{
/** Emitted when this execution context is disposed. */
disposed: undefined;
}>
implements Disposable
{
_client: CDPSession; _client: CDPSession;
_world: IsolatedWorld; _world: IsolatedWorld;
_contextId: number; _contextId: number;
_contextName?: string; _contextName?: string;
readonly #disposables = new DisposableStack(); readonly #disposables = new DisposableStack();
readonly #clientEmitter: EventEmitter<CDPSessionEvents>;
constructor( constructor(
client: CDPSession, client: CDPSession,
contextPayload: Protocol.Runtime.ExecutionContextDescription, contextPayload: Protocol.Runtime.ExecutionContextDescription,
world: IsolatedWorld world: IsolatedWorld
) { ) {
super();
this._client = client; this._client = client;
this._world = world; this._world = world;
this._contextId = contextPayload.id; this._contextId = contextPayload.id;
if (contextPayload.name) { if (contextPayload.name) {
this._contextName = contextPayload.name; this._contextName = contextPayload.name;
} }
this.#clientEmitter = this.#disposables.use(new EventEmitter(this._client)); const clientEmitter = this.#disposables.use(new EventEmitter(this._client));
this.#clientEmitter.on( clientEmitter.on('Runtime.bindingCalled', this.#onBindingCalled.bind(this));
'Runtime.bindingCalled', clientEmitter.on('Runtime.executionContextDestroyed', async event => {
this.#onBindingCalled.bind(this) if (event.executionContextId === this._contextId) {
); this[disposeSymbol]();
}
});
clientEmitter.on('Runtime.executionContextsCleared', async () => {
this[disposeSymbol]();
});
} }
// Contains mapping from functions that should be bound to Puppeteer functions. // Contains mapping from functions that should be bound to Puppeteer functions.
@ -456,6 +467,7 @@ export class ExecutionContext implements Disposable {
[disposeSymbol](): void { [disposeSymbol](): void {
this.#disposables.dispose(); this.#disposables.dispose();
this.emit('disposed', undefined);
} }
} }

View File

@ -122,8 +122,6 @@ export class FrameManager extends EventEmitter<FrameManagerEvents> {
* its frame tree and ID. * its frame tree and ID.
*/ */
async swapFrameTree(client: CDPSession): Promise<void> { async swapFrameTree(client: CDPSession): Promise<void> {
this.#onExecutionContextsCleared(this.#client);
this.#client = client; this.#client = client;
assert( assert(
this.#client instanceof CdpCDPSession, this.#client instanceof CdpCDPSession,
@ -188,14 +186,6 @@ export class FrameManager extends EventEmitter<FrameManagerEvents> {
await this.#frameTreeHandled?.valueOrThrow(); await this.#frameTreeHandled?.valueOrThrow();
this.#onExecutionContextCreated(event.context, session); this.#onExecutionContextCreated(event.context, session);
}); });
session.on('Runtime.executionContextDestroyed', async event => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onExecutionContextDestroyed(event.executionContextId, session);
});
session.on('Runtime.executionContextsCleared', async () => {
await this.#frameTreeHandled?.valueOrThrow();
this.#onExecutionContextsCleared(session);
});
session.on('Page.lifecycleEvent', async event => { session.on('Page.lifecycleEvent', async event => {
await this.#frameTreeHandled?.valueOrThrow(); await this.#frameTreeHandled?.valueOrThrow();
this.#onLifecycleEvent(event); this.#onLifecycleEvent(event);
@ -505,35 +495,15 @@ export class FrameManager extends EventEmitter<FrameManagerEvents> {
} }
const key = `${session.id()}:${contextPayload.id}`; const key = `${session.id()}:${contextPayload.id}`;
this.#contextIdToContext.set(key, context); this.#contextIdToContext.set(key, context);
} context.once('disposed', () => {
const key = `${session.id()}:${contextPayload.id}`;
#onExecutionContextDestroyed(
executionContextId: number,
session: CDPSession
): void {
const key = `${session.id()}:${executionContextId}`;
const context = this.#contextIdToContext.get(key); const context = this.#contextIdToContext.get(key);
if (!context) { if (!context) {
return; return;
} }
this.#contextIdToContext.delete(key); this.#contextIdToContext.delete(key);
if (context._world) {
context._world.clearContext(); context._world.clearContext();
} });
}
#onExecutionContextsCleared(session: CDPSession): void {
for (const [key, context] of this.#contextIdToContext.entries()) {
// Make sure to only clear execution contexts that belong
// to the current session.
if (context._client !== session) {
continue;
}
if (context._world) {
context._world.clearContext();
}
this.#contextIdToContext.delete(key);
}
} }
#removeFramesRecursively(frame: CdpFrame): void { #removeFramesRecursively(frame: CdpFrame): void {