Bug 1434855 - Improve performance of HAR export; r=ochameau
authorJan Odvarko <odvarko@gmail.com>
Thu, 08 Mar 2018 12:45:36 +0100
changeset 462189 470c96bdde515239728d90e12c7bae067884f909
parent 462188 73628e4869b31f1d06ebda2c8ea46ae038705bb9
child 462190 ccc9d9b8901575420db2b703d46f1ccc613621eb
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1434855
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1434855 - Improve performance of HAR export; r=ochameau MozReview-Commit-ID: 6H6P6wYmdQL
browser/components/extensions/test/browser/browser_ext_devtools_network.js
devtools/client/netmonitor/src/connector/chrome-connector.js
devtools/client/netmonitor/src/connector/firefox-connector.js
devtools/client/netmonitor/src/connector/firefox-data-provider.js
devtools/client/netmonitor/src/connector/index.js
devtools/client/netmonitor/src/har/har-exporter.js
--- a/browser/components/extensions/test/browser/browser_ext_devtools_network.js
+++ b/browser/components/extensions/test/browser/browser_ext_devtools_network.js
@@ -175,16 +175,18 @@ add_task(async function test_devtools_ne
   extension.sendMessage("navigate");
 
   // Wait till the navigation is complete and request
   // added into the net panel.
   await Promise.all([
     extension.awaitMessage("tabUpdated"),
     extension.awaitMessage("onNavigatedFired"),
     extension.awaitMessage("onRequestFinished"),
+    extension.awaitMessage("onRequestFinished-callbackExecuted"),
+    extension.awaitMessage("onRequestFinished-promiseResolved"),
     waitForRequestAdded(toolbox),
   ]);
 
   // Get HAR, it should not be empty now.
   const getHARPromise = extension.awaitMessage("getHAR-result");
   extension.sendMessage("getHAR");
   const getHARResult = await getHARPromise;
   is(getHARResult.log.entries.length, 1, "HAR log should not be empty");
--- a/devtools/client/netmonitor/src/connector/chrome-connector.js
+++ b/devtools/client/netmonitor/src/connector/chrome-connector.js
@@ -38,16 +38,20 @@ class ChromeConnector {
   pause() {
     this.disconnect();
   }
 
   resume() {
     this.setup();
   }
 
+  enableActions(enable) {
+    // TODO : implement.
+  }
+
   /**
    * currently all events are about "navigation" is not support on CDP
    */
   willNavigate() {
     this.actions.batchReset();
     this.actions.clearRequests();
   }
 
--- a/devtools/client/netmonitor/src/connector/firefox-connector.js
+++ b/devtools/client/netmonitor/src/connector/firefox-connector.js
@@ -122,16 +122,20 @@ class FirefoxConnector {
     }
     if (this.webConsoleClient) {
       this.webConsoleClient.off("networkEvent");
       this.webConsoleClient.off("networkEventUpdate");
       this.webConsoleClient.off("docEvent");
     }
   }
 
+  enableActions(enable) {
+    this.dataProvider.enableActions(enable);
+  }
+
   willNavigate() {
     if (!Services.prefs.getBoolPref("devtools.netmonitor.persistlog")) {
       this.actions.batchReset();
       this.actions.clearRequests();
     } else {
       // If the log is persistent, just clear all accumulated timing markers.
       this.actions.clearTimingMarkers();
     }
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -17,16 +17,17 @@ const { fetchHeaders } = require("../uti
  * so it's possible to determine whether all has been fetched
  * or not.
  */
 class FirefoxDataProvider {
   constructor({webConsoleClient, actions}) {
     // Options
     this.webConsoleClient = webConsoleClient;
     this.actions = actions;
+    this.actionsEnabled = true;
 
     // Internal properties
     this.payloadQueue = new Map();
 
     // Map[key string => Promise] used by `requestData` to prevent requesting the same
     // request data twice.
     this.lazyRequestData = new Map();
 
@@ -34,33 +35,42 @@ class FirefoxDataProvider {
     this.getLongString = this.getLongString.bind(this);
 
     // Event handlers
     this.onNetworkEvent = this.onNetworkEvent.bind(this);
     this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
   }
 
   /**
+   * Enable/disable firing redux actions (enabled by default).
+   *
+   * @param {boolean} enable Set to true to fire actions.
+   */
+  enableActions(enable) {
+    this.actionsEnabled = enable;
+  }
+
+  /**
    * Add a new network request to application state.
    *
    * @param {string} id request id
    * @param {object} data data payload will be added to application state
    */
   async addRequest(id, data) {
     let {
       method,
       url,
       isXHR,
       cause,
       startedDateTime,
       fromCache,
       fromServiceWorker,
     } = data;
 
-    if (this.actions.addRequest) {
+    if (this.actionsEnabled && this.actions.addRequest) {
       await this.actions.addRequest(id, {
         // Convert the received date/time string to a unix timestamp.
         startedMillis: Date.parse(startedDateTime),
         method,
         url,
         isXHR,
         cause,
 
@@ -115,17 +125,17 @@ class FirefoxDataProvider {
       responseContentObj,
       requestHeadersObj,
       responseHeadersObj,
       postDataObj,
       requestCookiesObj,
       responseCookiesObj
     );
 
-    if (this.actions.updateRequest) {
+    if (this.actionsEnabled && this.actions.updateRequest) {
       await this.actions.updateRequest(id, payload, true);
     }
 
     return payload;
   }
 
   async fetchResponseContent(responseContent) {
     let payload = {};
@@ -372,17 +382,17 @@ class FirefoxDataProvider {
 
     if (!payload.requestHeadersAvailable || !payload.requestCookiesAvailable ||
         !payload.eventTimingsAvailable || !payload.responseContentAvailable) {
       return;
     }
 
     this.payloadQueue.delete(actor);
 
-    if (this.actions.updateRequest) {
+    if (this.actionsEnabled && this.actions.updateRequest) {
       await this.actions.updateRequest(actor, payload, true);
     }
 
     // This event is fired only once per request, once all the properties are fetched
     // from `onNetworkEventUpdate`. There should be no more RDP requests after this.
     emit(EVENTS.PAYLOAD_READY, actor);
   }
 
@@ -409,17 +419,17 @@ class FirefoxDataProvider {
       return promise;
     }
     // Fetch the data
     promise = this._requestData(actor, method).then(async (payload) => {
       // Remove the request from the cache, any new call to requestData will fetch the
       // data again.
       this.lazyRequestData.delete(key);
 
-      if (this.actions.updateRequest) {
+      if (this.actionsEnabled && this.actions.updateRequest) {
         await this.actions.updateRequest(actor, {
           ...payload,
           // Lockdown *Available property once we fetch data from back-end.
           // Using this as a flag to prevent fetching arrived data again.
           [`${method}Available`]: false,
         }, true);
       }
 
--- a/devtools/client/netmonitor/src/connector/index.js
+++ b/devtools/client/netmonitor/src/connector/index.js
@@ -66,16 +66,20 @@ class Connector {
   pause() {
     return this.connector.pause();
   }
 
   resume() {
     return this.connector.resume();
   }
 
+  enableActions() {
+    this.connector.enableActions(...arguments);
+  }
+
   // Public API
 
   getLongString() {
     return this.connector.getLongString(...arguments);
   }
 
   getNetworkRequest() {
     return this.connector.getNetworkRequest(...arguments);
--- a/devtools/client/netmonitor/src/har/har-exporter.js
+++ b/devtools/client/netmonitor/src/har/har-exporter.js
@@ -190,28 +190,34 @@ const HarExporter = {
     let { connector } = options;
     let {
       getTabTarget,
     } = connector;
     let {
       form: { title, url }
     } = getTabTarget();
 
+    // Disconnect from redux actions/store.
+    connector.enableActions(false);
+
     options = {
       ...options,
       title: title || url,
       getString: connector.getLongString,
       getTimingMarker: connector.getTimingMarker,
       requestData: connector.requestData,
     };
 
     // Build HAR object from collected data.
     let builder = new HarBuilder(options);
     let result = await builder.build();
 
+    // Connect to redux actions again.
+    connector.enableActions(true);
+
     return result;
   },
 
   /**
    * Build JSON string from the HAR data object.
    */
   stringify: function (har) {
     if (!har) {