Bug 1416161 - Using redux-batched-subscribe + unstable_batchedUpdates to reduce Redux’s subscribed notifications r?honza draft
authorRicky Chien <ricky060709@gmail.com>
Fri, 10 Nov 2017 14:01:59 +0800
changeset 696163 3f518ceb7e792296493f354f2b57973fe727c440
parent 695940 ed94dc665071d8d510688ff50bbedad2c7cb33ee
child 739806 68985526dff7b69e965e08713a8ca1dc11aa4593
push id88657
push userbmo:rchien@mozilla.com
push dateFri, 10 Nov 2017 08:50:50 +0000
reviewershonza
bugs1416161
milestone58.0a1
Bug 1416161 - Using redux-batched-subscribe + unstable_batchedUpdates to reduce Redux’s subscribed notifications r?honza MozReview-Commit-ID: 2ooo35vy4fB
devtools/client/netmonitor/src/utils/create-store.js
devtools/client/netmonitor/src/utils/moz.build
devtools/client/netmonitor/src/utils/redux-batched-subscribe.js
--- a/devtools/client/netmonitor/src/utils/create-store.js
+++ b/devtools/client/netmonitor/src/utils/create-store.js
@@ -1,16 +1,22 @@
 /* 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 Services = require("Services");
-const { applyMiddleware, createStore } = require("devtools/client/shared/vendor/redux");
+const { unstable_batchedUpdates } = require("devtools/client/shared/vendor/react-dom"); // eslint-disable-line
+const {
+  applyMiddleware,
+  createStore,
+  compose,
+} = require("devtools/client/shared/vendor/redux");
+const { batchedSubscribe } = require("../utils/redux-batched-subscribe");
 
 // Middleware
 const batching = require("../middleware/batching");
 const prefs = require("../middleware/prefs");
 const thunk = require("../middleware/thunk");
 const recording = require("../middleware/recording");
 
 // Reducers
@@ -33,25 +39,27 @@ function configureStore(connector) {
     requests: new Requests(),
     sort: new Sort(),
     timingMarkers: new TimingMarkers(),
     ui: new UI({
       columns: getColumnState()
     }),
   };
 
-  // Prepare middleware.
-  let middleware = applyMiddleware(
-    thunk,
-    prefs,
-    batching,
-    recording(connector)
+  let enhancer = compose(
+    applyMiddleware(
+      thunk,
+      prefs,
+      batching,
+      recording(connector),
+    ),
+    batchedSubscribe(unstable_batchedUpdates),
   );
 
-  return createStore(rootReducer, initialState, middleware);
+  return createStore(rootReducer, initialState, enhancer);
 }
 
 // Helpers
 
 /**
  * Get column state from preferences.
  */
 function getColumnState() {
--- a/devtools/client/netmonitor/src/utils/moz.build
+++ b/devtools/client/netmonitor/src/utils/moz.build
@@ -8,12 +8,13 @@ DevToolsModules(
     'filter-autocomplete-provider.js',
     'filter-predicates.js',
     'filter-text-utils.js',
     'format-utils.js',
     'l10n.js',
     'mdn-utils.js',
     'menu.js',
     'prefs.js',
+    'redux-batched-subscribe.js',
     'request-utils.js',
     'sort-predicates.js',
     'sort-utils.js'
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/src/utils/redux-batched-subscribe.js
@@ -0,0 +1,75 @@
+/* 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";
+
+function batchedSubscribe(batch) {
+  if (typeof batch !== "function") {
+    throw new Error("Expected batch to be a function.");
+  }
+
+  let currentListeners = [];
+  let nextListeners = currentListeners;
+
+  function ensureCanMutateNextListeners() {
+    if (nextListeners === currentListeners) {
+      nextListeners = currentListeners.slice();
+    }
+  }
+
+  function subscribe(listener) {
+    if (typeof listener !== "function") {
+      throw new Error("Expected listener to be a function.");
+    }
+
+    let isSubscribed = true;
+
+    ensureCanMutateNextListeners();
+    nextListeners.push(listener);
+
+    return function unsubscribe() {
+      if (!isSubscribed) {
+        return;
+      }
+
+      isSubscribed = false;
+
+      ensureCanMutateNextListeners();
+      const index = nextListeners.indexOf(listener);
+      nextListeners.splice(index, 1);
+    };
+  }
+
+  function notifyListeners() {
+    const listeners = currentListeners = nextListeners;
+    for (let i = 0; i < listeners.length; i++) {
+      listeners[i]();
+    }
+  }
+
+  function notifyListenersBatched() {
+    batch(notifyListeners);
+  }
+
+  return next => (...args) => {
+    const store = next(...args);
+    const subscribeImmediate = store.subscribe;
+
+    function dispatch(...dispatchArgs) {
+      const res = store.dispatch(...dispatchArgs);
+      notifyListenersBatched();
+      return res;
+    }
+
+    return Object.assign({}, store, {
+      dispatch,
+      subscribe,
+      subscribeImmediate,
+    });
+  };
+}
+
+module.exports = {
+  batchedSubscribe,
+};