/** ***************************************** * Created by edonet@163.com * Created on 2020-01-17 11:04:52 ***************************************** */ 'use strict'; /** ***************************************** * 加载依赖 ***************************************** */ import { O, F } from './d'; import { setTimer } from './delay'; /** ***************************************** * 处理函数 ***************************************** */ 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 callback!: () => void; /** 取消函数 */ private cancel: (() => void) | undefined; /** 延时对象 */ private deferred: Promise | null = null; /** 执行函数 */ public invoke(context: O, args: unknown[]): unknown { // 更新计时器 if (this.deferred) { // 更新上下文 this.context = context; this.args = args; // 更新定时器 this.cancel && this.cancel(); this.cancel = setTimer(this.delay, this.callback); // 返回延时对象 return this.trailing ? this.deferred : this.result; } // 创建延时对象 this.deferred = new Promise(resolve => { // 创建回调整数 this.callback = () => { // 执行后延回调 if (this.trailing && this.args) { this.result = this.handler.apply(this.context, this.args); } // 返回结果 resolve(this.result); // 清空数据 this.context = null; this.args = null; this.result = undefined; this.cancel = undefined; this.deferred = null; }; // 创建定时器 this.cancel = setTimer(this.delay, this.callback); }); // 创建创建函数 if (this.leading) { // 执行函数 this.result = this.handler(...args); // 返回结果 return this.result; } // 更新上下文 this.context = context; this.args = args; // 返回延时对象 return this.deferred; } } /** ***************************************** * 配置 ***************************************** */ interface Options { delay?: number; leading?: boolean; trailing?: boolean; } /** ***************************************** * 去抖函数 ***************************************** */ type Debounce = ( T extends (...args: infer P) => infer Q ? (...args: P) => Q & Promise : never ); /** ***************************************** * 函数去抖 ***************************************** */ function debounce(handler: T): Debounce; function debounce(delay: number, handler: T): Debounce; function debounce(delay: number, handler: T, options: Options): Debounce; function debounce(handler: T, delay: number): Debounce; function debounce(handler: T, delay: number, options: Options): Debounce; function debounce(handler: T, options: Options): Debounce; function debounce(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: false, trailing: true }; // 合并配置 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 debounced(this: O, ...args: unknown[]): unknown { return timer.invoke(this, args); } // 返回结果 return debounced; } /** ***************************************** * 抛出模块 ***************************************** */ export { debounce };