UNPKG

puppeteer-core

Version:

A high-level API to control headless Chrome over the DevTools Protocol

185 lines (177 loc) 5.27 kB
/** * Copyright 2018 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const EventEmitter = require('events'); const {debugError} = require('./helper'); const {ExecutionContext} = require('./ExecutionContext'); const {JSHandle} = require('./JSHandle'); class Worker extends EventEmitter { /** * @param {Puppeteer.CDPSession} client * @param {string} url * @param {function(string, !Array<!JSHandle>, Protocol.Runtime.StackTrace=):void} consoleAPICalled * @param {function(!Protocol.Runtime.ExceptionDetails):void} exceptionThrown */ constructor(client, url, consoleAPICalled, exceptionThrown) { super(); this._client = client; this._url = url; this._executionContextPromise = new Promise(x => this._executionContextCallback = x); /** @type {function(!Protocol.Runtime.RemoteObject):!JSHandle} */ let jsHandleFactory; this._client.once('Runtime.executionContextCreated', /* async */ event => {return (fn => { const gen = fn.call(this); return new Promise((resolve, reject) => { function step(key, arg) { let info, value; try { info = gen[key](arg); value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( value => { step('next', value); }, err => { step('throw', err); }); } } return step('next'); }); })(function*(){ jsHandleFactory = remoteObject => new JSHandle(executionContext, client, remoteObject); const executionContext = new ExecutionContext(client, event.context, null); this._executionContextCallback(executionContext); });}); // This might fail if the target is closed before we recieve all execution contexts. this._client.send('Runtime.enable', {}).catch(debugError); this._client.on('Runtime.consoleAPICalled', event => consoleAPICalled(event.type, event.args.map(jsHandleFactory), event.stackTrace)); this._client.on('Runtime.exceptionThrown', exception => exceptionThrown(exception.exceptionDetails)); } /** * @return {string} */ url() { return this._url; } /** * @return {!Promise<ExecutionContext>} */ /* async */ executionContext() {return (fn => { const gen = fn.call(this); return new Promise((resolve, reject) => { function step(key, arg) { let info, value; try { info = gen[key](arg); value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( value => { step('next', value); }, err => { step('throw', err); }); } } return step('next'); }); })(function*(){ return this._executionContextPromise; });} /** * @param {Function|string} pageFunction * @param {!Array<*>} args * @return {!Promise<*>} */ /* async */ evaluate(pageFunction, ...args) {return (fn => { const gen = fn.call(this); return new Promise((resolve, reject) => { function step(key, arg) { let info, value; try { info = gen[key](arg); value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( value => { step('next', value); }, err => { step('throw', err); }); } } return step('next'); }); })(function*(){ return ((yield this._executionContextPromise)).evaluate(pageFunction, ...args); });} /** * @param {Function|string} pageFunction * @param {!Array<*>} args * @return {!Promise<!JSHandle>} */ /* async */ evaluateHandle(pageFunction, ...args) {return (fn => { const gen = fn.call(this); return new Promise((resolve, reject) => { function step(key, arg) { let info, value; try { info = gen[key](arg); value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then( value => { step('next', value); }, err => { step('throw', err); }); } } return step('next'); }); })(function*(){ return ((yield this._executionContextPromise)).evaluateHandle(pageFunction, ...args); });} } module.exports = {Worker};