plastiq-throttle
Version:
Throttle calls to a function, by arguments, by time, and by promise completion.
111 lines (93 loc) • 2.42 kB
JavaScript
var plastiq = require('plastiq');
var h = plastiq.html;
module.exports = function (options, fn) {
if (typeof options === 'function') {
fn = options;
options = undefined;
}
var refresh;
var throttle = options && options.hasOwnProperty('throttle') && options.throttle !== undefined? options.throttle: 140;
var promise, awaitingPromise, lastTime, lastValue, timeout;
var currentThis;
var currentArguments;
function callFn(callRefresh) {
var self = this;
if (promise) {
if (!awaitingPromise) {
promise.then(function () {
promise = undefined;
awaitingPromise = undefined;
sync();
}, function (e) {
promise = undefined;
awaitingPromise = undefined;
sync();
throw e;
});
awaitingPromise = true;
}
} else {
var result = fn.apply(currentThis, currentArguments);
if (result && typeof result.then === 'function') {
promise = result;
promise.then(function () {
promise = undefined;
refresh();
}, function (e) {
promise = undefined;
throw e;
});
}
valueChanged();
lastTime = Date.now();
if (callRefresh) {
refresh();
}
}
}
function valueHasChanged() {
if (!lastValue) {
return true;
}
if (currentArguments.length === 0 || lastValue.length !== currentArguments.length) {
return true;
}
for (var n = 0; n < lastValue.length; n++) {
if (lastValue[n] !== currentArguments[n]) {
return true;
}
}
}
function valueChanged() {
lastValue = currentArguments;
}
function sync() {
var self = this;
var now = Date.now();
if (valueHasChanged()) {
if (throttle === 0) {
callFn();
} else {
if (!lastTime || (lastTime + throttle < now)) {
callFn();
} else if (!timeout) {
var timeoutDuration = lastTime - now + throttle;
timeout = setTimeout(function () {
timeout = undefined;
callFn(true);
}, timeoutDuration);
}
}
}
}
function throttledFunction() {
refresh = h.refresh;
currentThis = this;
currentArguments = arguments;
sync();
}
throttledFunction.reset = function () {
lastValue = undefined;
};
return throttledFunction;
};