100 lines
2.4 KiB
JavaScript
100 lines
2.4 KiB
JavaScript
/* 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 () => 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,
|
|
};
|