vite-uni-dev-tool
Version:
vite-uni-dev-tool, debug, uni-app, 一处编写,到处调试
193 lines (164 loc) • 5.07 kB
text/typescript
type ThrottleOptions = {
leading?: boolean;
trailing?: boolean;
};
/**
* 创建一个节流函数,在指定时间间隔内只执行一次原函数
* @param func 需要节流的函数
* @param wait 等待时间(毫秒)
* @param options 配置选项
* @param options.leading 是否在开始时立即执行
* @param options.trailing 是否在延迟结束后执行最后一次调用
* @returns 节流后的函数
*/
export function throttle<T extends (...args: any[]) => any>(
func: T,
wait: number,
options: ThrottleOptions = {},
): (...args: Parameters<T>) => ReturnType<T> | undefined {
let timeout: NodeJS.Timeout | null = null;
let lastArgs: Parameters<T> | null = null;
let lastThis: any = null;
let result: ReturnType<T> | undefined;
let lastCallTime: number | null = null;
const { leading = true, trailing = true } = options;
const invokeFunc = (time: number) => {
const args = lastArgs;
const thisArg = lastThis;
lastArgs = lastThis = null;
lastCallTime = time;
result = func.apply(thisArg, args!);
return result;
};
const leadingEdge = (time: number) => {
lastCallTime = time;
timeout = null;
return leading ? invokeFunc(time) : undefined;
};
const trailingEdge = (time: number) => {
timeout = null;
if (lastArgs && trailing) {
return invokeFunc(time);
}
lastArgs = lastThis = null;
return result;
};
const remainingWait = (time: number) => {
if (lastCallTime === null) return wait;
const timeSinceLastCall = time - lastCallTime;
return wait - timeSinceLastCall;
};
const shouldInvoke = (time: number) => {
if (lastCallTime === null) return true;
const timeSinceLastCall = time - lastCallTime;
return timeSinceLastCall >= wait || timeSinceLastCall < 0;
};
const timerExpired = () => {
const time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
timeout = setTimeout(timerExpired, remainingWait(time));
return undefined;
};
const throttled = function (this: any, ...args: Parameters<T>) {
const time = Date.now();
const isInvoking = shouldInvoke(time);
lastArgs = args;
lastThis = this;
if (isInvoking) {
if (timeout === null) {
return leadingEdge(time);
}
}
if (timeout === null) {
timeout = setTimeout(timerExpired, wait);
}
return result;
};
throttled.cancel = () => {
if (timeout !== null) {
clearTimeout(timeout);
}
lastCallTime = null;
timeout = lastArgs = lastThis = null;
};
return throttled;
}
type DebouncedFunction<T extends (...args: any[]) => any> = ((
...args: Parameters<T>
) => ReturnType<T> | undefined) & {
cancel: () => void;
flush: () => ReturnType<T> | undefined;
};
/**
* 创建一个防抖函数,该函数在最后一次调用后等待指定时间才执行。
* @param func 需要防抖的函数
* @param wait 等待时间(毫秒)
* @param immediate 是否在第一次调用时立即执行
* @returns 防抖后的函数
*/
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number,
immediate: boolean = false,
): DebouncedFunction<T> {
let timeout: ReturnType<typeof setTimeout> | null = null;
let lastArgs: Parameters<T> | null = null;
let lastThis: ThisParameterType<T> | null = null;
let result: ReturnType<T> | undefined;
let lastCallTime: number | null = null;
const later = (): void => {
const last = lastCallTime !== null ? Date.now() - lastCallTime : 0;
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
if (lastArgs !== null && lastThis !== null) {
result = func.apply(lastThis, lastArgs);
lastArgs = lastThis = null;
}
}
}
};
const debounced = function (
this: ThisParameterType<T>,
...args: Parameters<T>
): ReturnType<T> | undefined {
lastArgs = args;
lastThis = this;
lastCallTime = Date.now();
const callNow = immediate && timeout === null;
if (!timeout) {
timeout = setTimeout(later, wait);
}
if (callNow) {
result = func.apply(this, args);
lastArgs = lastThis = null;
}
return result;
};
debounced.cancel = (): void => {
if (timeout !== null) {
clearTimeout(timeout);
timeout = null;
lastArgs = lastThis = null;
lastCallTime = null;
}
};
debounced.flush = (): ReturnType<T> | undefined => {
if (timeout !== null) {
clearTimeout(timeout);
timeout = null;
if (!immediate) {
if (lastArgs !== null && lastThis !== null) {
result = func.apply(lastThis, lastArgs);
lastArgs = lastThis = null;
}
}
}
return result;
};
return debounced;
}