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

Commit

Permalink
feat(debounce): add 'debounce' function (#191)
Browse files Browse the repository at this point in the history
Added a debounce function to prevent multiple function calls at a time

Closes: #190
  • Loading branch information
ordazgustavo authored and Kent C. Dodds committed Sep 9, 2018
1 parent 7808a04 commit 18379d4
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/debounce.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
export default debounce

/**
* Original Source: https://stackoverflow.com/questions/24004791/can-someone-explain-the-debounce-function-in-javascript
* This method will prevent functions to be called repeatedly
* @param {Function} func Function to debounce
* @param {Number} [delay=0] The number of milliseconds to delay the function call
* @param {Boolean} [immediate=false]
* Weather to call the function and then wait or vice versa
* @returns {Function} Returns the new debounced function.
* @example
* // Log the event after 1000ms of the last call
* const debounced = debounce(console.log, 1000)
* window.addEventListener('keyup', debounced)
*
* // Log the event immediately and wait 1000ms for the next call
* const debounced = debounce(console.log, 1000, true)
* window.addEventListener('keyup', debounced)
*
* // If 'delay' is falsy (except for 0), the function will not be debounced
* const debounced = debounce(console.log)
* window.addEventListener('keyup', debounced)
*/
function debounce(func, delay, immediate) {
let timeout
if (typeof func !== 'function') {
throw new TypeError('Expected a function')
}
return (...args) => {
const callNow = immediate && !timeout
if (!delay && delay !== 0) {
func(...args)
} else {
clearTimeout(timeout)

timeout = setTimeout(() => {
timeout = null
if (!immediate) {
func(...args)
}
}, delay)

if (callNow) {
func(...args)
}
}
}
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import fibonacciSum from './fibonacciSum'
import lcm from './lcm'
import occurrences from './occurrences'
import getMiddle from './getMiddle'
import debounce from './debounce'

export {
reverseArrayInPlace,
Expand Down Expand Up @@ -142,4 +143,5 @@ export {
lcm,
occurrences,
getMiddle,
debounce,
}
61 changes: 61 additions & 0 deletions test/debounce.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import test from 'ava'
import {debounce} from '../src'

let counter = 0
function incr() {
return counter++
}

function delay(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms)
})
}

test.beforeEach(t => {
counter = 0
t.is(counter, 0)
})

test('Throws error if first arg is not a function', t => {
const error = t.throws(() => debounce('hello'), TypeError)
t.is(error.message, 'Expected a function')
})

test('Should immediately return value', t => {
const debounced = debounce(incr)

debounced()
t.is(counter, 1)
debounced()
t.is(counter, 2)
debounced()
t.is(counter, 3)
})

test.serial('Should resolve after 50ms', async t => {
const wait = 50
const debounced = debounce(incr, wait)

debounced()
t.is(counter, 0)
debounced()
t.is(counter, 0)

await delay(wait + 1)
t.is(counter, 1)
})

test.serial('Should resolve immediately', async t => {
const wait = 50
const debounced = debounce(incr, wait, true)

debounced()
t.is(counter, 1)
debounced()
t.is(counter, 1)

await delay(wait + 1)
debounced()
t.is(counter, 2)
})

0 comments on commit 18379d4

Please sign in to comment.