2023-08-10 02:42:21 +08:00
|
|
|
/**
|
|
|
|
* Debounce function, includes leading and trailing options (lodash-like)
|
|
|
|
* @param {Function} func - function to be debounced
|
|
|
|
* @param {Number} delay - delay in milliseconds
|
|
|
|
* @param {Object} options - options object
|
|
|
|
* @param {Boolean} options.leading - whether to invoke the function on the leading edge
|
|
|
|
* @param {Boolean} options.trailing - whether to invoke the function on the trailing edge
|
|
|
|
* @returns {Function} - debounced function
|
|
|
|
*/
|
2023-08-10 00:06:27 +08:00
|
|
|
export function debounce(func, delay, options = {}) {
|
|
|
|
let timeoutId;
|
|
|
|
let lastArgs;
|
|
|
|
let lastThis;
|
|
|
|
let calledOnce = false;
|
|
|
|
|
|
|
|
const { leading = false, trailing = true } = options;
|
|
|
|
|
|
|
|
function invokeFunc() {
|
|
|
|
func.apply(lastThis, lastArgs);
|
|
|
|
lastArgs = null;
|
|
|
|
lastThis = null;
|
|
|
|
}
|
|
|
|
|
2024-06-18 03:25:31 +08:00
|
|
|
function scheduleTimeout() {
|
|
|
|
timeoutId = setTimeout(() => {
|
|
|
|
if (!trailing) {
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
timeoutId = null;
|
|
|
|
} else {
|
|
|
|
invokeFunc();
|
|
|
|
timeoutId = null;
|
|
|
|
}
|
|
|
|
calledOnce = false;
|
|
|
|
}, delay);
|
|
|
|
}
|
|
|
|
|
2023-08-10 00:06:27 +08:00
|
|
|
return function (...args) {
|
|
|
|
lastArgs = args;
|
|
|
|
lastThis = this;
|
|
|
|
|
|
|
|
if (!timeoutId) {
|
|
|
|
if (leading && !calledOnce) {
|
|
|
|
invokeFunc();
|
|
|
|
calledOnce = true;
|
|
|
|
}
|
|
|
|
|
2024-06-18 03:25:31 +08:00
|
|
|
scheduleTimeout();
|
2023-08-10 00:06:27 +08:00
|
|
|
} else if (trailing) {
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
timeoutId = setTimeout(() => {
|
|
|
|
invokeFunc();
|
|
|
|
timeoutId = null;
|
|
|
|
}, delay);
|
2024-06-18 03:25:31 +08:00
|
|
|
} else if (leading && calledOnce) {
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
scheduleTimeout();
|
2023-08-10 00:06:27 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|