2023-03-02 21:25:08 +08:00
|
|
|
export function throttle(func, delay, options = {}) {
|
|
|
|
let timeoutId;
|
|
|
|
let lastExecTime = 0;
|
|
|
|
let leadingExec = true;
|
|
|
|
|
|
|
|
const { leading = true, trailing = true } = options;
|
|
|
|
|
2023-08-25 01:49:05 +08:00
|
|
|
let cancelPendingExecution = false; // Flag to track cancellation
|
|
|
|
|
|
|
|
const throttledFunction = function () {
|
2023-03-02 21:25:08 +08:00
|
|
|
const context = this;
|
|
|
|
const args = arguments;
|
|
|
|
const elapsed = Date.now() - lastExecTime;
|
|
|
|
|
|
|
|
function execute() {
|
2023-08-25 01:49:05 +08:00
|
|
|
if (!cancelPendingExecution) { // Only execute if not cancelled
|
|
|
|
func.apply(context, args);
|
|
|
|
lastExecTime = Date.now();
|
|
|
|
}
|
2023-03-02 21:25:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (leadingExec && leading) {
|
|
|
|
execute();
|
|
|
|
leadingExec = false;
|
2023-09-27 00:50:51 +08:00
|
|
|
const nextExecDelay = elapsed < delay ? delay - elapsed : 0;
|
|
|
|
setTimeout(function () {
|
|
|
|
leadingExec = true;
|
|
|
|
}, nextExecDelay);
|
2023-03-02 21:25:08 +08:00
|
|
|
} else if (!timeoutId && trailing) {
|
|
|
|
timeoutId = setTimeout(function () {
|
|
|
|
execute();
|
|
|
|
timeoutId = null;
|
|
|
|
}, delay - elapsed);
|
|
|
|
}
|
2023-08-25 01:49:05 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Add a cancel method to the throttled function
|
|
|
|
throttledFunction.cancel = function () {
|
|
|
|
cancelPendingExecution = true;
|
|
|
|
clearTimeout(timeoutId);
|
|
|
|
timeoutId = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
return throttledFunction;
|
2023-03-02 21:25:08 +08:00
|
|
|
}
|