Skip to content
This repository was archived by the owner on Feb 20, 2019. It is now read-only.

Commit 18379d4

Browse files
ordazgustavoKent C. Dodds
authored and
Kent C. Dodds
committed
feat(debounce): add 'debounce' function (#191)
Added a debounce function to prevent multiple function calls at a time Closes: #190
1 parent 7808a04 commit 18379d4

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed

Diff for: src/debounce.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
export default debounce
2+
3+
/**
4+
* Original Source: https://stackoverflow.com/questions/24004791/can-someone-explain-the-debounce-function-in-javascript
5+
* This method will prevent functions to be called repeatedly
6+
* @param {Function} func Function to debounce
7+
* @param {Number} [delay=0] The number of milliseconds to delay the function call
8+
* @param {Boolean} [immediate=false]
9+
* Weather to call the function and then wait or vice versa
10+
* @returns {Function} Returns the new debounced function.
11+
* @example
12+
* // Log the event after 1000ms of the last call
13+
* const debounced = debounce(console.log, 1000)
14+
* window.addEventListener('keyup', debounced)
15+
*
16+
* // Log the event immediately and wait 1000ms for the next call
17+
* const debounced = debounce(console.log, 1000, true)
18+
* window.addEventListener('keyup', debounced)
19+
*
20+
* // If 'delay' is falsy (except for 0), the function will not be debounced
21+
* const debounced = debounce(console.log)
22+
* window.addEventListener('keyup', debounced)
23+
*/
24+
function debounce(func, delay, immediate) {
25+
let timeout
26+
if (typeof func !== 'function') {
27+
throw new TypeError('Expected a function')
28+
}
29+
return (...args) => {
30+
const callNow = immediate && !timeout
31+
if (!delay && delay !== 0) {
32+
func(...args)
33+
} else {
34+
clearTimeout(timeout)
35+
36+
timeout = setTimeout(() => {
37+
timeout = null
38+
if (!immediate) {
39+
func(...args)
40+
}
41+
}, delay)
42+
43+
if (callNow) {
44+
func(...args)
45+
}
46+
}
47+
}
48+
}

Diff for: src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import fibonacciSum from './fibonacciSum'
6969
import lcm from './lcm'
7070
import occurrences from './occurrences'
7171
import getMiddle from './getMiddle'
72+
import debounce from './debounce'
7273

7374
export {
7475
reverseArrayInPlace,
@@ -142,4 +143,5 @@ export {
142143
lcm,
143144
occurrences,
144145
getMiddle,
146+
debounce,
145147
}

Diff for: test/debounce.test.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import test from 'ava'
2+
import {debounce} from '../src'
3+
4+
let counter = 0
5+
function incr() {
6+
return counter++
7+
}
8+
9+
function delay(ms) {
10+
return new Promise(resolve => {
11+
setTimeout(() => resolve(), ms)
12+
})
13+
}
14+
15+
test.beforeEach(t => {
16+
counter = 0
17+
t.is(counter, 0)
18+
})
19+
20+
test('Throws error if first arg is not a function', t => {
21+
const error = t.throws(() => debounce('hello'), TypeError)
22+
t.is(error.message, 'Expected a function')
23+
})
24+
25+
test('Should immediately return value', t => {
26+
const debounced = debounce(incr)
27+
28+
debounced()
29+
t.is(counter, 1)
30+
debounced()
31+
t.is(counter, 2)
32+
debounced()
33+
t.is(counter, 3)
34+
})
35+
36+
test.serial('Should resolve after 50ms', async t => {
37+
const wait = 50
38+
const debounced = debounce(incr, wait)
39+
40+
debounced()
41+
t.is(counter, 0)
42+
debounced()
43+
t.is(counter, 0)
44+
45+
await delay(wait + 1)
46+
t.is(counter, 1)
47+
})
48+
49+
test.serial('Should resolve immediately', async t => {
50+
const wait = 50
51+
const debounced = debounce(incr, wait, true)
52+
53+
debounced()
54+
t.is(counter, 1)
55+
debounced()
56+
t.is(counter, 1)
57+
58+
await delay(wait + 1)
59+
debounced()
60+
t.is(counter, 2)
61+
})

0 commit comments

Comments
 (0)