diff --git a/packages/vtable/__tests__/debounce.test.ts b/packages/vtable/__tests__/debounce.test.ts new file mode 100644 index 000000000..83a487063 --- /dev/null +++ b/packages/vtable/__tests__/debounce.test.ts @@ -0,0 +1,41 @@ +import { debounce } from '../src/tools/debounce'; + +jest.mock('@src/vrender', () => ({ vglobal: {} })); + +describe('debounce', () => { + test('waits for the remaining delay after a call during the debounce window', () => { + let now = 1000; + const timers: { callback: () => void; delay: number }[] = []; + const callback = jest.fn(); + jest.spyOn(Date, 'now').mockImplementation(() => now); + jest.spyOn(globalThis, 'setTimeout').mockImplementation((handler, delay) => { + timers.push({ callback: handler as () => void, delay: delay as number }); + return timers.length as any; + }); + + try { + const debounced = debounce(callback, 100); + debounced('first'); + now = 1050; + debounced('latest'); + + now = 1100; + timers.shift()!.callback(); + expect(callback).not.toHaveBeenCalled(); + expect(timers[0].delay).toBe(50); + + // 提前触发时仍等待最后 1ms,避免过早调用用户回调。 + now = 1149; + timers.shift()!.callback(); + expect(callback).not.toHaveBeenCalled(); + expect(timers[0].delay).toBe(1); + + now = 1150; + timers.shift()!.callback(); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith('latest'); + } finally { + jest.restoreAllMocks(); + } + }); +}); diff --git a/packages/vtable/src/tools/debounce.ts b/packages/vtable/src/tools/debounce.ts index 6a6eee01a..d684ff1b6 100644 --- a/packages/vtable/src/tools/debounce.ts +++ b/packages/vtable/src/tools/debounce.ts @@ -88,13 +88,14 @@ export function debounce(func: Function, wait?: number, options?: any) { return result; } + // 计算尾调用前的剩余等待时间,避免连续调用时反复创建零延迟定时器。 function remainingWait(time: number) { // 计算 time 与最近一次调用 debounced 函数的时间差 const timeSinceLastCall = time - lastCallTime; // 计算 time 与最近一次调用 func 函数的时间差 const timeSinceLastInvoke = time - lastInvokeTime; // 用 wait 减去已经等待的时间 - const timeWaiting = wait && -timeSinceLastCall; + const timeWaiting = (wait as number) - timeSinceLastCall; return maxing ? Math.min(timeWaiting as number, maxWait - timeSinceLastInvoke) : timeWaiting; }