Skip to content

Commit 5cadbb8

Browse files
committed
Add 'debounce' util
1 parent a89f5fe commit 5cadbb8

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

src/utils/debounce.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import '@testing-library/jest-dom/extend-expect'
2+
3+
import { debounce } from './debounce'
4+
5+
describe('debounce', () => {
6+
beforeEach(() => {
7+
jest.resetAllMocks()
8+
jest.useFakeTimers()
9+
})
10+
11+
it('returns a debounced function that only gets called after the specified period of time', () => {
12+
const timeout = 100
13+
const testName = 'Billy'
14+
const testNum = 42
15+
const fn = jest.fn((name: string, num: number) => `Hi ${name} ${num}`)
16+
const debounced = debounce(fn, timeout)
17+
18+
expect(typeof debounced).toBe('function')
19+
expect(fn).toHaveBeenCalledTimes(0)
20+
21+
debounced(testName, testNum)
22+
expect(fn).toHaveBeenCalledTimes(0)
23+
24+
// calls a few times and advance timers by "less than timeout"
25+
jest.advanceTimersByTime(10)
26+
debounced(testName, testNum)
27+
jest.advanceTimersByTime(20)
28+
debounced(testName, testNum)
29+
jest.advanceTimersByTime(timeout - 1)
30+
expect(fn).toHaveBeenCalledTimes(0)
31+
32+
// now call, advance to timeout, and ensure it got called and returned correctly
33+
debounced(testName, testNum)
34+
jest.advanceTimersByTime(timeout)
35+
expect(fn).toHaveBeenCalledTimes(1)
36+
expect(fn).toHaveBeenLastCalledWith(testName, testNum)
37+
expect(fn).toHaveReturnedWith('Hi Billy 42')
38+
})
39+
})

src/utils/debounce.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2+
export const debounce = (fn: (...args) => any, timeout: number) => {
3+
const debounceTimeout = Math.max(timeout, 1)
4+
let currentTimeout
5+
6+
return (...args) => {
7+
if (currentTimeout) {
8+
clearTimeout(currentTimeout)
9+
}
10+
11+
return new Promise(resolve => {
12+
currentTimeout = setTimeout(() => {
13+
resolve(fn(...args))
14+
}, debounceTimeout)
15+
})
16+
}
17+
}

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './classNames'
2+
export * from './debounce'
23
export * from './keycodes'
34
export * from './wrap'

0 commit comments

Comments
 (0)