summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/redux/middleware/debounce.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/shared/redux/middleware/debounce.js')
-rw-r--r--devtools/client/shared/redux/middleware/debounce.js100
1 files changed, 100 insertions, 0 deletions
diff --git a/devtools/client/shared/redux/middleware/debounce.js b/devtools/client/shared/redux/middleware/debounce.js
new file mode 100644
index 0000000000..fc5625a0fe
--- /dev/null
+++ b/devtools/client/shared/redux/middleware/debounce.js
@@ -0,0 +1,100 @@
+/* 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";
+
+/**
+ * Redux middleware for debouncing actions.
+ *
+ * Schedules actions with { meta: { debounce: true } } to be delayed
+ * by wait milliseconds. If another action is fired during this
+ * time-frame both actions are inserted into a queue and delayed.
+ * Maximum delay is defined by maxWait argument.
+ *
+ * Handling more actions at once results in better performance since
+ * components need to be re-rendered less often.
+ *
+ * @param string wait Wait for specified amount of milliseconds
+ * before executing an action. The time is used
+ * to collect more actions and handle them all
+ * at once.
+ * @param string maxWait Max waiting time. It's used in case of
+ * a long stream of actions.
+ */
+function debounceActions(wait, maxWait) {
+ let queuedActions = [];
+
+ return store => next => {
+ const debounced = debounce(
+ () => {
+ next(batchActions(queuedActions));
+ queuedActions = [];
+ },
+ wait,
+ maxWait
+ );
+
+ return action => {
+ if (!action.meta || !action.meta.debounce) {
+ return next(action);
+ }
+
+ if (!wait || !maxWait) {
+ return next(action);
+ }
+
+ if (action.type == BATCH_ACTIONS) {
+ queuedActions.push(...action.actions);
+ } else {
+ queuedActions.push(action);
+ }
+
+ return debounced();
+ };
+ };
+}
+
+function debounce(cb, wait, maxWait) {
+ let timeout, maxTimeout;
+ const doFunction = () => {
+ clearTimeout(timeout);
+ clearTimeout(maxTimeout);
+ timeout = maxTimeout = null;
+ cb();
+ };
+
+ return () => {
+ return new Promise(resolve => {
+ const onTimeout = () => {
+ doFunction();
+ resolve();
+ };
+
+ clearTimeout(timeout);
+
+ timeout = setTimeout(onTimeout, wait);
+ if (!maxTimeout) {
+ maxTimeout = setTimeout(onTimeout, maxWait);
+ }
+ });
+ };
+}
+
+const BATCH_ACTIONS = Symbol("BATCH_ACTIONS");
+
+/**
+ * Action creator for action-batching.
+ */
+function batchActions(batchedActions, debounceFlag = true) {
+ return {
+ type: BATCH_ACTIONS,
+ meta: { debounce: debounceFlag },
+ actions: batchedActions,
+ };
+}
+
+module.exports = {
+ BATCH_ACTIONS,
+ batchActions,
+ debounceActions,
+};