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 {
|
class Navigator {
|
||||||
/**
|
/**
|
||||||
* @param {!Connection} client
|
* @param {!Connection} client
|
||||||
|
* @param {string} url
|
||||||
|
* @param {string=} referrer
|
||||||
* @param {!Object=} options
|
* @param {!Object=} options
|
||||||
*/
|
*/
|
||||||
constructor(client, options = {}) {
|
constructor(client, url, referrer, options = {}) {
|
||||||
this._client = client;
|
this._client = client;
|
||||||
this._minTime = typeof options.minTime === 'number' ? options.minTime : 0;
|
this._url = url;
|
||||||
this._maxTime = typeof options.maxTime === 'number' ? options.maxTime : 30000;
|
this._referrer = referrer;
|
||||||
this._idleTime = typeof options.networkIdleTimeout === 'number' ? options.networkIdleTimeout : 1000;
|
this._maxTime = typeof options['maxTime'] === 'number' ? options['maxTime'] : 30000;
|
||||||
this._idleInflight = typeof options.networkIdleInflight === 'number' ? options.networkIdleInflight : 2;
|
this._idleTime = typeof options['networkIdleTimeout'] === 'number' ? options['networkIdleTimeout'] : 1000;
|
||||||
this._waitFor = typeof options.waitFor === 'string' ? options.waitFor : 'load';
|
this._idleInflight = typeof options['networkIdleInflight'] === 'number' ? options['networkIdleInflight'] : 2;
|
||||||
this._inflightRequests = 0;
|
this._waitFor = typeof options['waitFor'] === 'string' ? options['waitFor'] : 'load';
|
||||||
|
|
||||||
console.assert(this._waitFor === 'load' || this._waitFor === 'networkidle', 'Unknown value for options.waitFor: ' + this._waitFor);
|
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
|
* @return {!Promise<boolean>}
|
||||||
* @param {string=} referrer
|
|
||||||
*/
|
*/
|
||||||
async navigate(url, referrer) {
|
async navigate() {
|
||||||
this._requestIds = new Set();
|
this._init();
|
||||||
this._navigationStartTime = Date.now();
|
let certificateError = new Promise(fulfill => this._client.once('Security.certificateError', fulfill)).then(() => false);
|
||||||
this._idleReached = 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 navigationComplete;
|
let watchdog = new Promise(fulfill => setTimeout(fulfill, this._maxTime)).then(() => false);
|
||||||
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);
|
|
||||||
|
|
||||||
// Await for the command to throw exception in case of illegal arguments.
|
// Await for the command to throw exception in case of illegal arguments.
|
||||||
try {
|
try {
|
||||||
await this._client.send('Page.navigate', {url, referrer});
|
await this._client.send('Page.navigate', {url: this._url, referrer: this._referrer});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
this._cleanup();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Promise.race([navigationComplete.then(() => true), navigationFailure]).then(retVal => {
|
let result = await Promise.race([certificateError, watchdog, this._waitFor === 'load' ? loadEventFired : networkIdle]);
|
||||||
clearTimeout(this._idleTimer);
|
this._cleanup();
|
||||||
clearTimeout(this._minimumTimer);
|
return result;
|
||||||
clearTimeout(this._maximumTimer);
|
|
||||||
return retVal;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,26 +78,31 @@ class Navigator {
|
|||||||
|
|
||||||
--this._inflightRequests;
|
--this._inflightRequests;
|
||||||
if (this._inflightRequests <= this._idleInflight && !this._idleTimer)
|
if (this._inflightRequests <= this._idleInflight && !this._idleTimer)
|
||||||
this._idleTimer = setTimeout(this._onIdleReached.bind(this), this._idleTime);
|
this._idleTimer = setTimeout(this._networkIdleCallback, this._idleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onIdleReached() {
|
_init() {
|
||||||
this._idleReached = true;
|
this._loadingStartedHandler = this._onLoadingStarted.bind(this);
|
||||||
this._completeNavigation(false);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
_cleanup() {
|
||||||
* @param {boolean} force
|
this._client.removeListener('Network.requestWillBeSent', this._loadingStartedHandler);
|
||||||
*/
|
this._client.removeListener('Network.loadingFinished', this._loadingCompletedHandler);
|
||||||
_completeNavigation(force) {
|
this._client.removeListener('Network.loadingFailed', this._loadingCompletedHandler);
|
||||||
if (!this._navigationLoadCallback)
|
this._client.removeListener('Network.webSocketCreated', this._loadingStartedHandler);
|
||||||
return;
|
this._client.removeListener('Network.webSocketClosed', this._loadingCompletedHandler);
|
||||||
|
|
||||||
const elapsedTime = Date.now() - this._navigationStartTime;
|
clearTimeout(this._idleTimer);
|
||||||
if ((elapsedTime >= this._minTime && this._idleReached) || force) {
|
clearTimeout(this._maximumTimer);
|
||||||
this._navigationLoadCallback();
|
|
||||||
this._navigationLoadCallback = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ class Page extends EventEmitter {
|
|||||||
* @return {!Promise<boolean>}
|
* @return {!Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
navigate(url, options) {
|
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