/** ***************************************** * Created by edonet@163.com * Created on 2021-03-21 19:25:05 ***************************************** */ 'use strict'; /** ***************************************** * 加载依赖 ***************************************** */ import { O, F } from './d'; import { delay } from './defer'; /** ***************************************** * 处理函数 ***************************************** */ type Handler = (...args: unknown[]) => unknown; /** ***************************************** * 计时对象 ***************************************** */ class Timer { /** 去抖函数 */ public handler!: Handler; /** 去抖延时 */ public delay!: number | undefined; /** 先导配置 */ public leading!: boolean; /** 后延配置 */ public trailing!: boolean; /** 调用上下文 */ private context: O | null = null; /** 调用参数 */ private args: unknown[] | null = null; /** 执行结果 */ private result: unknown; /** 延时对象 */ private deferred: Promise | null = null; /** 执行计时器 */ public invoke(context: O | null, args: unknown[]): unknown { // 更新计时器 if (this.deferred) { // 更新上下文 this.context = context; this.args = args; // 返回延时对象 return this.leading ? this.result : this.deferred; } // 创建延时对象 this.deferred = this.defer(); // 创建创建函数 if (this.leading) { // 执行函数 this.result = this.handler.apply(context, args); // 返回结果 return this.result; } // 更新上下文 this.context = context; this.args = args; // 返回延时对象 return this.deferred; } /** 生成延时对象 */ private defer(): Promise { return delay(this.delay, () => { let result = this.result, deferred = null; // 执行后延回调 if (this.args && this.trailing) { // 执行回调 result = this.handler.apply(this.context, this.args); // 创建一下帧延时 deferred = this.defer(); } // 清空数据 this.context = null; this.args = null; this.result = undefined; this.deferred = deferred; // 返回结果 return result; }); } } /** ***************************************** * 配置 ***************************************** */ interface Options { delay?: number; leading?: boolean; trailing?: boolean; } /** ***************************************** * 去抖函数 ***************************************** */ type Throttle = ( T extends (...args: infer P) => infer Q ? (...args: P) => Q | Promise : never ); /** ***************************************** * 函数去抖 ***************************************** */ function throttle(handler: T): Throttle; function throttle(delay: number, handler: T): Throttle; function throttle(delay: number, handler: T, options: Options): Throttle; function throttle(handler: T, delay: number): Throttle; function throttle(handler: T, delay: number, options: Options): Throttle; function throttle(handler: T, options: Options): Throttle; function throttle(handler: unknown, delay?: unknown, options?: unknown): unknown { // 重载参数 if (typeof delay === 'function') { [handler, delay] = [delay, handler]; } // 校验参数 if (typeof handler !== 'function') { throw new TypeError('param `handler` expected a function'); } // 创建计时器 const timer = new Timer(); const opts: Options = { leading: true, trailing: false }; // 合并配置 Object.assign(opts, typeof delay === 'number' ? { delay } : delay, options); // 配置计时器 timer.handler = handler as Handler; timer.delay = opts.delay; timer.leading = opts.leading === true; timer.trailing = opts.trailing !== false; // 生成去抖函数 function throttled(this: O, ...args: unknown[]): unknown { return timer.invoke(this, args); } // 返回去抖函数 return throttled; } /** ***************************************** * 抛出接口 ***************************************** */ export { throttle };