Cleanup navigator logic
This patch cleans up navigator logic. (This is a result of a pair programming with @pavelfeldman).
This commit is contained in:
parent
090ecfa6b9
commit
f7cd0048af
@ -17,64 +17,43 @@
|
||||
class Navigator {
|
||||
/**
|
||||
* @param {!Connection} client
|
||||
* @param {string} url
|
||||
* @param {string=} referrer
|
||||
* @param {!Object=} options
|
||||
*/
|
||||
constructor(client, options = {}) {
|
||||
constructor(client, url, referrer, options = {}) {
|
||||
this._client = client;
|
||||
this._minTime = typeof options.minTime === 'number' ? options.minTime : 0;
|
||||
this._maxTime = typeof options.maxTime === 'number' ? options.maxTime : 30000;
|
||||
this._idleTime = typeof options.networkIdleTimeout === 'number' ? options.networkIdleTimeout : 1000;
|
||||
this._idleInflight = typeof options.networkIdleInflight === 'number' ? options.networkIdleInflight : 2;
|
||||
this._waitFor = typeof options.waitFor === 'string' ? options.waitFor : 'load';
|
||||
this._inflightRequests = 0;
|
||||
this._url = url;
|
||||
this._referrer = referrer;
|
||||
this._maxTime = typeof options['maxTime'] === 'number' ? options['maxTime'] : 30000;
|
||||
this._idleTime = typeof options['networkIdleTimeout'] === 'number' ? options['networkIdleTimeout'] : 1000;
|
||||
this._idleInflight = typeof options['networkIdleInflight'] === 'number' ? options['networkIdleInflight'] : 2;
|
||||
this._waitFor = typeof options['waitFor'] === 'string' ? options['waitFor'] : 'load';
|
||||
|
||||
console.assert(this._waitFor === 'load' || this._waitFor === 'networkidle', 'Unknown value for options.waitFor: ' + this._waitFor);
|
||||
|
||||
if (this._waitFor === 'networkidle') {
|
||||
client.on('Network.requestWillBeSent', event => this._onLoadingStarted(event));
|
||||
client.on('Network.loadingFinished', event => this._onLoadingCompleted(event));
|
||||
client.on('Network.loadingFailed', event => this._onLoadingCompleted(event));
|
||||
client.on('Network.webSocketCreated', event => this._onLoadingStarted(event));
|
||||
client.on('Network.webSocketClosed', event => this._onLoadingCompleted(event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {string=} referrer
|
||||
* @return {!Promise<boolean>}
|
||||
*/
|
||||
async navigate(url, referrer) {
|
||||
this._requestIds = new Set();
|
||||
this._navigationStartTime = Date.now();
|
||||
this._idleReached = false;
|
||||
|
||||
let navigationComplete;
|
||||
let navigationFailure = new Promise(fulfill => this._client.once('Security.certificateError', fulfill)).then(() => false);
|
||||
|
||||
if (this._waitFor === 'load')
|
||||
navigationComplete = new Promise(fulfill => this._client.once('Page.loadEventFired', fulfill));
|
||||
else
|
||||
navigationComplete = new Promise(fulfill => this._navigationLoadCallback = fulfill);
|
||||
|
||||
this._inflightRequests = 0;
|
||||
|
||||
this._minimumTimer = setTimeout(this._completeNavigation.bind(this, false), this._minTime);
|
||||
this._maximumTimer = setTimeout(this._completeNavigation.bind(this, true), this._maxTime);
|
||||
this._idleTimer = setTimeout(this._onIdleReached.bind(this), this._idleTime);
|
||||
async navigate() {
|
||||
this._init();
|
||||
let certificateError = new Promise(fulfill => this._client.once('Security.certificateError', fulfill)).then(() => false);
|
||||
let networkIdle = new Promise(fulfill => this._networkIdleCallback = fulfill).then(() => true);
|
||||
let loadEventFired = new Promise(fulfill => this._client.once('Page.loadEventFired', fulfill)).then(() => true);
|
||||
let watchdog = new Promise(fulfill => setTimeout(fulfill, this._maxTime)).then(() => false);
|
||||
|
||||
// Await for the command to throw exception in case of illegal arguments.
|
||||
try {
|
||||
await this._client.send('Page.navigate', {url, referrer});
|
||||
await this._client.send('Page.navigate', {url: this._url, referrer: this._referrer});
|
||||
} catch (e) {
|
||||
this._cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
return await Promise.race([navigationComplete.then(() => true), navigationFailure]).then(retVal => {
|
||||
clearTimeout(this._idleTimer);
|
||||
clearTimeout(this._minimumTimer);
|
||||
clearTimeout(this._maximumTimer);
|
||||
return retVal;
|
||||
});
|
||||
let result = await Promise.race([certificateError, watchdog, this._waitFor === 'load' ? loadEventFired : networkIdle]);
|
||||
this._cleanup();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,26 +78,31 @@ class Navigator {
|
||||
|
||||
--this._inflightRequests;
|
||||
if (this._inflightRequests <= this._idleInflight && !this._idleTimer)
|
||||
this._idleTimer = setTimeout(this._onIdleReached.bind(this), this._idleTime);
|
||||
this._idleTimer = setTimeout(this._networkIdleCallback, this._idleTime);
|
||||
}
|
||||
|
||||
_onIdleReached() {
|
||||
this._idleReached = true;
|
||||
this._completeNavigation(false);
|
||||
_init() {
|
||||
this._loadingStartedHandler = this._onLoadingStarted.bind(this);
|
||||
this._loadingCompletedHandler = this._onLoadingCompleted.bind(this);
|
||||
this._client.on('Network.requestWillBeSent', this._loadingStartedHandler);
|
||||
this._client.on('Network.loadingFinished', this._loadingCompletedHandler);
|
||||
this._client.on('Network.loadingFailed', this._loadingCompletedHandler);
|
||||
this._client.on('Network.webSocketCreated', this._loadingStartedHandler);
|
||||
this._client.on('Network.webSocketClosed', this._loadingCompletedHandler);
|
||||
|
||||
this._inflightRequests = 0;
|
||||
this._requestIds = new Set();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} force
|
||||
*/
|
||||
_completeNavigation(force) {
|
||||
if (!this._navigationLoadCallback)
|
||||
return;
|
||||
_cleanup() {
|
||||
this._client.removeListener('Network.requestWillBeSent', this._loadingStartedHandler);
|
||||
this._client.removeListener('Network.loadingFinished', this._loadingCompletedHandler);
|
||||
this._client.removeListener('Network.loadingFailed', this._loadingCompletedHandler);
|
||||
this._client.removeListener('Network.webSocketCreated', this._loadingStartedHandler);
|
||||
this._client.removeListener('Network.webSocketClosed', this._loadingCompletedHandler);
|
||||
|
||||
const elapsedTime = Date.now() - this._navigationStartTime;
|
||||
if ((elapsedTime >= this._minTime && this._idleReached) || force) {
|
||||
this._navigationLoadCallback();
|
||||
this._navigationLoadCallback = null;
|
||||
}
|
||||
clearTimeout(this._idleTimer);
|
||||
clearTimeout(this._maximumTimer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ class Page extends EventEmitter {
|
||||
* @return {!Promise<boolean>}
|
||||
*/
|
||||
navigate(url, options) {
|
||||
return new Navigator(this._client, options).navigate(url, this._networkManager.httpHeaders().referer);
|
||||
return new Navigator(this._client, url, this._networkManager.httpHeaders().referer, options).navigate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user