@oxog/delay
Version:
A comprehensive, zero-dependency delay/timeout utility library with advanced timing features
206 lines • 6.33 kB
JavaScript
export function throttle(fn, ms, options = {}) {
const { leading = true, trailing = true } = options;
let lastCallTime = 0;
let lastInvokeTime = 0;
let timerId;
let lastArgs;
let lastThis;
let result;
function invokeFunc(time) {
const args = lastArgs;
const thisArg = lastThis;
lastArgs = undefined;
lastThis = undefined;
lastInvokeTime = time;
result = fn.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
lastInvokeTime = time;
timerId = setTimeout(timerExpired, ms);
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
const timeWaiting = ms - timeSinceLastCall;
return Math.min(timeWaiting, ms - timeSinceLastInvoke);
}
function shouldInvoke(time) {
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
return (lastCallTime === 0 ||
timeSinceLastCall >= ms ||
timeSinceLastCall < 0 ||
timeSinceLastInvoke >= ms);
}
function timerExpired() {
const time = Date.now();
if (shouldInvoke(time)) {
trailingEdge(time);
}
else {
timerId = setTimeout(timerExpired, remainingWait(time));
}
}
function trailingEdge(time) {
timerId = undefined;
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = undefined;
lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
if (typeof timerId === 'number') {
clearTimeout(timerId);
}
else {
clearTimeout(timerId);
}
}
lastInvokeTime = 0;
lastArgs = undefined;
lastCallTime = 0;
lastThis = undefined;
timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now());
}
function throttled(...args) {
const time = Date.now();
const isInvoking = shouldInvoke(time);
lastArgs = args;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (trailing) {
timerId = setTimeout(timerExpired, ms);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, ms);
}
return result;
}
throttled.cancel = cancel;
throttled.flush = flush;
return throttled;
}
export function debounce(fn, ms, options = {}) {
const { leading = false, trailing = true, maxWait } = options;
let lastCallTime = 0;
let lastInvokeTime = 0;
let timerId;
let maxTimerId;
let lastArgs;
let lastThis;
let result;
function invokeFunc(time) {
const args = lastArgs;
const thisArg = lastThis;
lastArgs = undefined;
lastThis = undefined;
lastInvokeTime = time;
result = fn.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
lastInvokeTime = time;
timerId = setTimeout(timerExpired, ms);
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
const timeWaiting = ms - timeSinceLastCall;
return maxWait === undefined
? timeWaiting
: Math.min(timeWaiting, maxWait - timeSinceLastInvoke);
}
function shouldInvoke(time) {
const timeSinceLastCall = time - lastCallTime;
const timeSinceLastInvoke = time - lastInvokeTime;
return (lastCallTime === 0 ||
timeSinceLastCall >= ms ||
timeSinceLastCall < 0 ||
(maxWait !== undefined && timeSinceLastInvoke >= maxWait));
}
function timerExpired() {
const time = Date.now();
if (shouldInvoke(time)) {
trailingEdge(time);
}
else {
timerId = setTimeout(timerExpired, remainingWait(time));
}
}
function trailingEdge(time) {
timerId = undefined;
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = undefined;
lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
if (typeof timerId === 'number') {
clearTimeout(timerId);
}
else {
clearTimeout(timerId);
}
}
if (maxTimerId !== undefined) {
if (typeof maxTimerId === 'number') {
clearTimeout(maxTimerId);
}
else {
clearTimeout(maxTimerId);
}
}
lastInvokeTime = 0;
lastArgs = undefined;
lastCallTime = 0;
lastThis = undefined;
timerId = undefined;
maxTimerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now());
}
function debounced(...args) {
const time = Date.now();
const isInvoking = shouldInvoke(time);
lastArgs = args;
lastThis = this;
lastCallTime = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCallTime);
}
if (maxWait !== undefined) {
timerId = setTimeout(timerExpired, ms);
maxTimerId = setTimeout(timerExpired, maxWait);
return leading ? invokeFunc(lastCallTime) : result;
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, ms);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
//# sourceMappingURL=throttle-debounce.js.map