Bug 1411887 - Add telemetry to track console refresh time when reload a page. r=nchevobbe draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Tue, 24 Oct 2017 11:56:58 -0700
changeset 687748 04bcfeb6f9bc042938d0c769a28f0db6aefd6766
parent 687532 ecef003d836730c07ecfcfa25df8e71a88aec99f
child 737727 17dc8881bbbccd64a8b5d3e70508398c19bbaf5c
push id86589
push userbmo:poirot.alex@gmail.com
push dateFri, 27 Oct 2017 17:22:46 +0000
reviewersnchevobbe
bugs1411887
milestone58.0a1
Bug 1411887 - Add telemetry to track console refresh time when reload a page. r=nchevobbe MozReview-Commit-ID: 8zZyq9suJWB
devtools/client/framework/toolbox.js
devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
devtools/client/webconsole/new-webconsole.js
devtools/client/webconsole/panel.js
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -1984,18 +1984,18 @@ Toolbox.prototype = {
     });
   },
 
   /**
    * Fired when user just started navigating away to another web page.
    */
   async _onWillNavigate() {
     let toolId = this.currentToolId;
-    // For now, only inspector fires "reloaded" event
-    if (toolId != "inspector") {
+    // For now, only inspector and webconsole fires "reloaded" event
+    if (toolId != "inspector" && toolId != "webconsole") {
       return;
     }
 
     let start = this.win.performance.now();
     let panel = this.getPanel(toolId);
     // Ignore the timing if the panel is still loading
     if (!panel) {
       return;
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -27,17 +27,17 @@ function NewConsoleOutputWrapper(parentN
   this.owner = owner;
   this.document = document;
 
   this.init = this.init.bind(this);
 
   this.queuedMessageAdds = [];
   this.queuedMessageUpdates = [];
   this.queuedRequestUpdates = [];
-  this.throttledDispatchTimeout = false;
+  this.throttledDispatchPromise = null;
 
   store = configureStore(this.jsterm.hud);
 }
 NewConsoleOutputWrapper.prototype = {
   init: function () {
     const attachRefToHud = (id, node) => {
       this.jsterm.hud[id] = node;
     };
@@ -265,50 +265,63 @@ NewConsoleOutputWrapper.prototype = {
     this.setTimeoutIfNeeded();
   },
 
   batchedMessagesAdd: function (message) {
     this.queuedMessageAdds.push(message);
     this.setTimeoutIfNeeded();
   },
 
+  /**
+   * Returns a Promise that resolves once any async dispatch is finally dispatched.
+   */
+  waitAsyncDispatches: function () {
+    if (!this.throttledDispatchPromise) {
+      return Promise.resolve();
+    }
+    return this.throttledDispatchPromise;
+  },
+
   setTimeoutIfNeeded: function () {
-    if (this.throttledDispatchTimeout) {
+    if (this.throttledDispatchPromise) {
       return;
     }
 
-    this.throttledDispatchTimeout = setTimeout(() => {
-      this.throttledDispatchTimeout = null;
+    this.throttledDispatchPromise = new Promise(done => {
+      setTimeout(() => {
+        this.throttledDispatchPromise = null;
 
-      store.dispatch(actions.messagesAdd(this.queuedMessageAdds));
-      this.queuedMessageAdds = [];
+        store.dispatch(actions.messagesAdd(this.queuedMessageAdds));
+        this.queuedMessageAdds = [];
 
-      if (this.queuedMessageUpdates.length > 0) {
-        this.queuedMessageUpdates.forEach(({ message, res }) => {
-          store.dispatch(actions.networkMessageUpdate(message, null, res));
-          this.jsterm.hud.emit("network-message-updated", res);
-        });
-        this.queuedMessageUpdates = [];
-      }
-      if (this.queuedRequestUpdates.length > 0) {
-        this.queuedRequestUpdates.forEach(({ id, data}) => {
-          store.dispatch(actions.networkUpdateRequest(id, data));
-        });
-        this.queuedRequestUpdates = [];
+        if (this.queuedMessageUpdates.length > 0) {
+          this.queuedMessageUpdates.forEach(({ message, res }) => {
+            store.dispatch(actions.networkMessageUpdate(message, null, res));
+            this.jsterm.hud.emit("network-message-updated", res);
+          });
+          this.queuedMessageUpdates = [];
+        }
+        if (this.queuedRequestUpdates.length > 0) {
+          this.queuedRequestUpdates.forEach(({ id, data}) => {
+            store.dispatch(actions.networkUpdateRequest(id, data));
+          });
+          this.queuedRequestUpdates = [];
 
-        // Fire an event indicating that all data fetched from
-        // the backend has been received. This is based on
-        // 'FirefoxDataProvider.isQueuePayloadReady', see more
-        // comments in that method.
-        // (netmonitor/src/connector/firefox-data-provider).
-        // This event might be utilized in tests to find the right
-        // time when to finish.
-        this.jsterm.hud.emit("network-request-payload-ready");
-      }
-    }, 50);
+          // Fire an event indicating that all data fetched from
+          // the backend has been received. This is based on
+          // 'FirefoxDataProvider.isQueuePayloadReady', see more
+          // comments in that method.
+          // (netmonitor/src/connector/firefox-data-provider).
+          // This event might be utilized in tests to find the right
+          // time when to finish.
+          this.jsterm.hud.emit("network-request-payload-ready");
+        }
+        done();
+      }, 50);
+    });
   },
 
   // Should be used for test purpose only.
   getStore: function () {
     return store;
   }
 };
 
--- a/devtools/client/webconsole/new-webconsole.js
+++ b/devtools/client/webconsole/new-webconsole.js
@@ -301,34 +301,42 @@ NewWebConsoleFrame.prototype = {
   /**
    * Handler for the tabNavigated notification.
    *
    * @param string event
    *        Event name.
    * @param object packet
    *        Notification packet received from the server.
    */
-  handleTabNavigated: function (event, packet) {
+  handleTabNavigated: async function (event, packet) {
     if (event == "will-navigate") {
+      this._navigationStart = this.window.performance.now();
       if (this.persistLog) {
         // Add a _type to hit convertCachedPacket.
         packet._type = true;
         this.newConsoleOutput.dispatchMessageAdd(packet);
       } else {
         this.clearOutput(false);
       }
     }
 
     if (packet.url) {
       this.onLocationChange(packet.url, packet.title);
     }
 
     if (event == "navigate" && !packet.nativeConsoleAPI) {
       this.logWarningAboutReplacedAPI();
     }
+
+    if (event == "navigate") {
+      // Wait for completion of any async dispatch before notifying that the console
+      // is fully updated after a page reload
+      await this.newConsoleOutput.waitAsyncDispatches();
+      this.emit("reloaded");
+    }
   },
 
   clearOutput(clearStorage) {
     this.newConsoleOutput.dispatchMessagesClear();
     this.webConsoleClient.clearNetworkRequests();
     if (clearStorage) {
       this.webConsoleClient.clearMessagesCache();
     }
--- a/devtools/client/webconsole/panel.js
+++ b/devtools/client/webconsole/panel.js
@@ -76,16 +76,21 @@ WebConsolePanel.prototype = {
 
         let webConsoleUIWindow = iframe.contentWindow.wrappedJSObject;
         let chromeWindow = iframe.ownerDocument.defaultView;
         return HUDService.openWebConsole(this.target, webConsoleUIWindow,
                                          chromeWindow);
       })
       .then((webConsole) => {
         this.hud = webConsole;
+        // Pipe 'reloaded' event from NewWebConsoleFrame to WebConsolePanel.
+        // These events are listened by the Toolbox.
+        this.hud.ui.on("reloaded", () => {
+          this.emit("reloaded");
+        });
         this._isReady = true;
         this.emit("ready");
         return this;
       }, (reason) => {
         let msg = "WebConsolePanel open failed. " +
                   reason.error + ": " + reason.message;
         dump(msg + "\n");
         console.error(msg, reason);