Do not leak event listeners on navigation

This patch:
- introduces helper.addEventListener/helper.removeEventListeners
  to simplify event management
- moves NavigatorWatchdog over to the helper.addEventListener to
  stop leaking event listeners
This commit is contained in:
Andrey Lushnikov
2017-07-22 17:03:58 -07:00
parent 5757bc18f2
commit c4904b4e10
3 changed files with 56 additions and 27 deletions

View File

@@ -15,6 +15,7 @@
*/
const NetworkManager = require('./NetworkManager');
const helper = require('./helper');
class NavigatorWatcher {
/**
@@ -37,19 +38,37 @@ class NavigatorWatcher {
* @return {!Promise<!Map<string, !Response>>}
*/
async waitForNavigation() {
this._init();
this._inflightRequests = 0;
this._requestIds = new Set();
/** @type {!Map<string, !Response>} */
this._responses = new Map();
this._eventListeners = [
helper.addEventListener(this._client, 'Network.requestWillBeSent', this._onLoadingStarted.bind(this)),
helper.addEventListener(this._client, 'Network.loadingFinished', this._onLoadingCompleted.bind(this)),
helper.addEventListener(this._client, 'Network.loadingFailed', this._onLoadingCompleted.bind(this)),
helper.addEventListener(this._client, 'Network.webSocketCreated', this._onLoadingStarted.bind(this)),
helper.addEventListener(this._client, 'Network.webSocketClosed', this._onLoadingCompleted.bind(this)),
helper.addEventListener(this._networkManager, NetworkManager.Events.Response, this._onResponse.bind(this)),
];
let certificateError = new Promise(fulfill => {
this._eventListeners.push(helper.addEventListener(this._client, 'Security.certificateError', fulfill));
}).then(error => 'SSL Certificate error: ' + error.errorType);
let certificateError = new Promise(fulfill => this._client.once('Security.certificateError', fulfill))
.then(error => new Error('SSL Certiciate error: ' + error.errorType));
let networkIdle = new Promise(fulfill => this._networkIdleCallback = fulfill).then(() => null);
let loadEventFired = new Promise(fulfill => this._client.once('Page.loadEventFired', fulfill)).then(() => null);
let watchdog = new Promise(fulfill => this._maximumTimer = setTimeout(fulfill, this._timeout)).then(() => new Error('Navigation Timeout Exceeded: ' + this._timeout + 'ms exceeded'));
let loadEventFired = new Promise(fulfill => {
this._eventListeners.push(helper.addEventListener(this._client, 'Page.loadEventFired', fulfill));
}).then(() => null);
let watchdog = new Promise(fulfill => this._maximumTimer = setTimeout(fulfill, this._timeout))
.then(() => 'Navigation Timeout Exceeded: ' + this._timeout + 'ms exceeded');
try {
// Await for the command to throw exception in case of illegal arguments.
const error = await Promise.race([certificateError, watchdog, this._waitUntil === 'load' ? loadEventFired : networkIdle]);
if (error)
throw error;
throw new Error(error);
return this._responses;
} finally {
this._cleanup();
@@ -86,29 +105,10 @@ class NavigatorWatcher {
}
_init() {
this._loadingStartedHandler = this._onLoadingStarted.bind(this);
this._loadingCompletedHandler = this._onLoadingCompleted.bind(this);
this._onResponseHandler = this._onResponse.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._networkManager.on(NetworkManager.Events.Response, this._onResponseHandler);
this._inflightRequests = 0;
this._requestIds = new Set();
/** @type {!Map<string, !Response>} */
this._responses = new Map();
}
_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);
this._networkManager.removeListener(NetworkManager.Events.Response, this._onResponseHandler);
helper.removeEventListeners(this._eventListeners);
clearTimeout(this._idleTimer);
clearTimeout(this._maximumTimer);