Bug 1434848 - StatusBar tries to updates on every state update and its render is slow. r=Honza
authorHemakshi Sachdev <sachdev.hemakshi@gmail.com>
Tue, 02 Apr 2019 12:09:30 +0000
changeset 526382 2c9d39de3650cc49b8b9ddeff086ac59c38ed34b
parent 526378 b77d8a690be81945fa6739479f1fe19180935e35
child 526383 3e83e4d61954d7fb2e1446fc503b0de9a2a5bc20
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1434848
milestone68.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 1434848 - StatusBar tries to updates on every state update and its render is slow. r=Honza Converted StatusBar to a Component and added a `shouldComponentUpdate` method to prevent unnecessary updates. Differential Revision: https://phabricator.services.mozilla.com/D24599
devtools/client/netmonitor/src/components/StatusBar.js
--- a/devtools/client/netmonitor/src/components/StatusBar.js
+++ b/devtools/client/netmonitor/src/components/StatusBar.js
@@ -1,57 +1,90 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+const { Component } = require("devtools/client/shared/vendor/react");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
 const { PluralForm } = require("devtools/shared/plural-form");
 const Actions = require("../actions/index");
 const {
   getDisplayedRequestsSummary,
   getDisplayedTimingMarker,
 } = require("../selectors/index");
 const {
   getFormattedSize,
   getFormattedTime,
 } = require("../utils/format-utils");
 const { L10N } = require("../utils/l10n");
+const { propertiesEqual } = require("../utils/request-utils");
 
 const { button, div } = dom;
 
 const REQUESTS_COUNT_EMPTY = L10N.getStr("networkMenu.summary.requestsCountEmpty");
 const TOOLTIP_PERF = L10N.getStr("networkMenu.summary.tooltip.perf");
 const TOOLTIP_REQUESTS_COUNT = L10N.getStr("networkMenu.summary.tooltip.requestsCount");
 const TOOLTIP_TRANSFERRED = L10N.getStr("networkMenu.summary.tooltip.transferred");
 const TOOLTIP_FINISH = L10N.getStr("networkMenu.summary.tooltip.finish");
 const TOOLTIP_DOM_CONTENT_LOADED =
         L10N.getStr("networkMenu.summary.tooltip.domContentLoaded");
 const TOOLTIP_LOAD = L10N.getStr("networkMenu.summary.tooltip.load");
 
-function StatusBar({ summary, openStatistics, timingMarkers }) {
-  const { count, contentSize, transferredSize, millis } = summary;
-  const {
-    DOMContentLoaded,
-    load,
-  } = timingMarkers;
+const UPDATED_SUMMARY_PROPS = [
+  "count",
+  "contentSize",
+  "transferredSize",
+  "millis",
+];
+
+const UPDATED_TIMING_PROPS = [
+  "DOMContentLoaded",
+  "load",
+];
 
-  const countText = count === 0 ? REQUESTS_COUNT_EMPTY :
-    PluralForm.get(count,
-      L10N.getStr("networkMenu.summary.requestsCount2")).replace("#1", count);
-  const transferText = L10N.getFormatStrWithNumbers("networkMenu.summary.transferred",
-    getFormattedSize(contentSize), getFormattedSize(transferredSize));
-  const finishText = L10N.getFormatStrWithNumbers("networkMenu.summary.finish",
-    getFormattedTime(millis));
+/**
+ * Status Bar component
+ * Displays the summary of total size and transferred size by all requests
+ * Also displays different timing markers
+ */
+class StatusBar extends Component {
+  static get propTypes() {
+    return {
+      connector: PropTypes.object.isRequired,
+      openStatistics: PropTypes.func.isRequired,
+      summary: PropTypes.object.isRequired,
+      timingMarkers: PropTypes.object.isRequired,
+    };
+  }
 
-  return (
-    div({ className: "devtools-toolbar devtools-toolbar-bottom" },
+  shouldComponentUpdate(nextProps) {
+    const { summary, timingMarkers } = this.props;
+    return !propertiesEqual(UPDATED_SUMMARY_PROPS, summary, nextProps.summary) ||
+      !propertiesEqual(UPDATED_TIMING_PROPS, timingMarkers, nextProps.timingMarkers);
+  }
+
+  render() {
+    const { openStatistics, summary, timingMarkers } = this.props;
+    const { count, contentSize, transferredSize, millis } = summary;
+    const { DOMContentLoaded, load } = timingMarkers;
+
+    const countText = count === 0 ? REQUESTS_COUNT_EMPTY :
+      PluralForm.get(count,
+        L10N.getStr("networkMenu.summary.requestsCount2")).replace("#1", count);
+    const transferText = L10N.getFormatStrWithNumbers("networkMenu.summary.transferred",
+      getFormattedSize(contentSize), getFormattedSize(transferredSize));
+    const finishText = L10N.getFormatStrWithNumbers("networkMenu.summary.finish",
+      getFormattedTime(millis));
+
+    return (
+      div({ className: "devtools-toolbar devtools-toolbar-bottom" },
       button({
         className: "devtools-button requests-list-network-summary-button",
         title: TOOLTIP_PERF,
         onClick: openStatistics,
       },
         div({ className: "summary-info-icon" }),
       ),
       div({
@@ -73,29 +106,21 @@ function StatusBar({ summary, openStatis
           className: "status-bar-label dom-content-loaded",
           title: TOOLTIP_DOM_CONTENT_LOADED,
         }, `DOMContentLoaded: ${getFormattedTime(DOMContentLoaded)}`),
       load > -1 &&
         div({
           className: "status-bar-label load",
           title: TOOLTIP_LOAD,
         }, `load: ${getFormattedTime(load)}`),
-    )
-  );
+      )
+    );
+  }
 }
 
-StatusBar.displayName = "StatusBar";
-
-StatusBar.propTypes = {
-  connector: PropTypes.object.isRequired,
-  openStatistics: PropTypes.func.isRequired,
-  summary: PropTypes.object.isRequired,
-  timingMarkers: PropTypes.object.isRequired,
-};
-
 module.exports = connect(
   (state) => ({
     summary: getDisplayedRequestsSummary(state),
     timingMarkers: {
       DOMContentLoaded:
         getDisplayedTimingMarker(state, "firstDocumentDOMContentLoadedTimestamp"),
       load: getDisplayedTimingMarker(state, "firstDocumentLoadTimestamp"),
     },