From b9b24cf963a503ddeb9ff34ea74a40e40a265c2e Mon Sep 17 00:00:00 2001 From: jrandolf <101637635+jrandolf@users.noreply.github.com> Date: Mon, 22 Aug 2022 14:03:45 +0200 Subject: [PATCH] chore: use deferred promises in web worker (#8824) --- .../puppeteer.webworker.executioncontext.md | 4 +- docs/api/puppeteer.webworker.md | 2 +- src/common/WebWorker.ts | 61 ++++++++----------- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/docs/api/puppeteer.webworker.executioncontext.md b/docs/api/puppeteer.webworker.executioncontext.md index 39b2a607..1db00f6c 100644 --- a/docs/api/puppeteer.webworker.executioncontext.md +++ b/docs/api/puppeteer.webworker.executioncontext.md @@ -4,7 +4,9 @@ sidebar_label: WebWorker.executionContext # WebWorker.executionContext() method -Returns the ExecutionContext the WebWorker runs in +> Warning: This API is now obsolete. +> +> Do not use directly. **Signature:** diff --git a/docs/api/puppeteer.webworker.md b/docs/api/puppeteer.webworker.md index 91d89fda..cc48ca04 100644 --- a/docs/api/puppeteer.webworker.md +++ b/docs/api/puppeteer.webworker.md @@ -42,5 +42,5 @@ for (const worker of page.workers()) { | ----------------------------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [evaluate(pageFunction, args)](./puppeteer.webworker.evaluate.md) | | If the function passed to the worker.evaluate returns a Promise, then worker.evaluate would wait for the promise to resolve and return its value. If the function passed to the worker.evaluate returns a non-serializable value, then worker.evaluate resolves to undefined. DevTools Protocol also supports transferring some additional values that are not serializable by JSON: -0, NaN, Infinity, -Infinity, and bigint literals. Shortcut for await worker.executionContext()).evaluate(pageFunction, ...args). | | [evaluateHandle(pageFunction, args)](./puppeteer.webworker.evaluatehandle.md) | | The only difference between worker.evaluate and worker.evaluateHandle is that worker.evaluateHandle returns in-page object (JSHandle). If the function passed to the worker.evaluateHandle returns a Promise, then worker.evaluateHandle would wait for the promise to resolve and return its value. Shortcut for await worker.executionContext()).evaluateHandle(pageFunction, ...args) | -| [executionContext()](./puppeteer.webworker.executioncontext.md) | | Returns the ExecutionContext the WebWorker runs in | +| [executionContext()](./puppeteer.webworker.executioncontext.md) | | | | [url()](./puppeteer.webworker.url.md) | | | diff --git a/src/common/WebWorker.ts b/src/common/WebWorker.ts index 97d144c7..83495267 100644 --- a/src/common/WebWorker.ts +++ b/src/common/WebWorker.ts @@ -21,6 +21,7 @@ import {EventEmitter} from './EventEmitter.js'; import {ExecutionContext} from './ExecutionContext.js'; import {JSHandle} from './JSHandle.js'; import {debugError} from './util.js'; +import {createDeferredPromise} from '../util/DeferredPromise.js'; /** * @internal @@ -38,8 +39,6 @@ export type ExceptionThrownCallback = ( details: Protocol.Runtime.ExceptionDetails ) => void; -type JSHandleFactory = (obj: Protocol.Runtime.RemoteObject) => JSHandle; - /** * This class represents a * {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | WebWorker}. @@ -67,10 +66,10 @@ type JSHandleFactory = (obj: Protocol.Runtime.RemoteObject) => JSHandle; * @public */ export class WebWorker extends EventEmitter { + #executionContext = createDeferredPromise(); + #client: CDPSession; #url: string; - #executionContextPromise: Promise; - #executionContextCallback!: (value: ExecutionContext) => void; /** * @internal @@ -84,32 +83,36 @@ export class WebWorker extends EventEmitter { super(); this.#client = client; this.#url = url; - this.#executionContextPromise = new Promise(x => { - return (this.#executionContextCallback = x); - }); - let jsHandleFactory: JSHandleFactory; this.#client.once('Runtime.executionContextCreated', async event => { - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - jsHandleFactory = remoteObject => { - return new JSHandle(executionContext, client, remoteObject); - }; - const executionContext = new ExecutionContext(client, event.context); - this.#executionContextCallback(executionContext); + const context = new ExecutionContext(client, event.context); + this.#executionContext.resolve(context); }); - - // This might fail if the target is closed before we receive all execution contexts. - this.#client.send('Runtime.enable').catch(debugError); - this.#client.on('Runtime.consoleAPICalled', event => { + this.#client.on('Runtime.consoleAPICalled', async event => { + const context = await this.#executionContext; return consoleAPICalled( event.type, - event.args.map(jsHandleFactory), + event.args.map((object: Protocol.Runtime.RemoteObject) => { + return new JSHandle(context, this.#client, object); + }), event.stackTrace ); }); this.#client.on('Runtime.exceptionThrown', exception => { return exceptionThrown(exception.exceptionDetails); }); + + // This might fail if the target is closed before we receive all execution contexts. + this.#client.send('Runtime.enable').catch(debugError); + } + + /** + * @deprecated Do not use directly. + * + * @returns The ExecutionContext the web worker runs in. + */ + async executionContext(): Promise { + return this.#executionContext; } /** @@ -119,14 +122,6 @@ export class WebWorker extends EventEmitter { return this.#url; } - /** - * Returns the ExecutionContext the WebWorker runs in - * @returns The ExecutionContext the web worker runs in. - */ - async executionContext(): Promise { - return this.#executionContextPromise; - } - /** * If the function passed to the `worker.evaluate` returns a Promise, then * `worker.evaluate` would wait for the promise to resolve and return its @@ -148,10 +143,8 @@ export class WebWorker extends EventEmitter { pageFunction: Func | string, ...args: Params ): Promise>> { - return (await this.#executionContextPromise).evaluate( - pageFunction, - ...args - ); + const context = await this.#executionContext; + return context.evaluate(pageFunction, ...args); } /** @@ -173,9 +166,7 @@ export class WebWorker extends EventEmitter { pageFunction: Func | string, ...args: Params ): Promise>>> { - return (await this.#executionContextPromise).evaluateHandle( - pageFunction, - ...args - ); + const context = await this.#executionContext; + return context.evaluateHandle(pageFunction, ...args); } }