From 6065256b88986b0e754e64dc8251b9b67ef30380 Mon Sep 17 00:00:00 2001 From: Adam C Hamlin Date: Fri, 12 Jul 2024 23:58:19 -0400 Subject: [PATCH] fix: debounce cancel should clear pending timeout --- docs/curry/debounce.mdx | 2 +- src/curry/debounce.ts | 16 ++++++---------- tests/curry/debounce.test.ts | 21 +++++++++++++++------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/curry/debounce.mdx b/docs/curry/debounce.mdx index e2bd9ddb1..837896dde 100644 --- a/docs/curry/debounce.mdx +++ b/docs/curry/debounce.mdx @@ -34,7 +34,7 @@ Source Invocations: - - - - - - - - - - x - - - - - - - - - - - - - - - - - x - ### Cancel -The function returned by `debounce` has a `cancel` method that when called will permanently stop the source function from being debounced. +The function returned by `debounce` has a `cancel` method that when called will cancel any pending invocation. ```ts const debounced = _.debounce({ delay: 100 }, api.feed.refresh) diff --git a/src/curry/debounce.ts b/src/curry/debounce.ts index a09f815ef..9aa9c5a46 100644 --- a/src/curry/debounce.ts +++ b/src/curry/debounce.ts @@ -41,24 +41,20 @@ export function debounce( func: (...args: TArgs) => any, ): DebounceFunction { let timer: unknown = undefined - let active = true const debounced: DebounceFunction = (...args: TArgs) => { - if (active) { - clearTimeout(timer) - timer = setTimeout(() => { - active && func(...args) - timer = undefined - }, delay) - } else { + clearTimeout(timer) + timer = setTimeout(() => { func(...args) - } + timer = undefined + }, delay) } debounced.isPending = () => { return timer !== undefined } debounced.cancel = () => { - active = false + clearTimeout(timer) + timer = undefined } debounced.flush = (...args: TArgs) => func(...args) diff --git a/tests/curry/debounce.test.ts b/tests/curry/debounce.test.ts index 1c0d2bd56..65c16994d 100644 --- a/tests/curry/debounce.test.ts +++ b/tests/curry/debounce.test.ts @@ -27,14 +27,23 @@ describe('debounce', () => { expect(mockFunc).toHaveBeenCalledTimes(1) }) - test('does not debounce after cancel is called', () => { - runFunc3Times() + test('does not execute if cancel called before timeout', () => { + func() + expect(func.isPending()).toBe(true); + func.cancel() + expect(func.isPending()).toBe(false); + vi.advanceTimersByTime(delay + 10) expect(mockFunc).toHaveBeenCalledTimes(0) + }) + + test('continues to debounce after cancel is called', () => { + func() func.cancel() - runFunc3Times() - expect(mockFunc).toHaveBeenCalledTimes(3) - runFunc3Times() - expect(mockFunc).toHaveBeenCalledTimes(6) + vi.advanceTimersByTime(delay + 10) + expect(mockFunc).toHaveBeenCalledTimes(0) + func() + vi.advanceTimersByTime(delay + 10) + expect(mockFunc).toHaveBeenCalledTimes(1) }) test('executes the function immediately when the flush method is called', () => {