Skip to content

Commit

Permalink
feat(throttle): add throttle utility function
Browse files Browse the repository at this point in the history
  • Loading branch information
stfsy committed Apr 19, 2023
1 parent b036407 commit 558ed67
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/utils/throttle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export const createThrottleFn = () => {
return function (callback, limit) {
let blocked = false
let unblockTimeoutId = 0
let finalCallbackTimeoutId = 0

/**
* Calls the throttle function. Callbacks will be throttled according limit
* given to constructor function
* @returns
*/
function f() {
if (blocked) {
return
}

blocked = true
clearTimeout(finalCallbackTimeoutId)
callback.call()

unblockTimeoutId = setTimeout(() => { blocked = false }, limit)
finalCallbackTimeoutId = setTimeout(callback, limit + 5)
}

/**
* Clears internal timeouts and intervals to prevent further calls
*/
f.clear = function () {
clearTimeout(unblockTimeoutId)
clearTimeout(finalCallbackTimeoutId)
}

return f
}
}
50 changes: 50 additions & 0 deletions tests/unit/utils/throttle.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { expect } from 'chai';
import { createThrottleFn } from '../../../src/utils/throttle.js';

describe('throttle', () => {

it('executes the first callback immediately', () => {
const throttle = createThrottleFn()
let throttledCallbacks = 0
throttle(() => {
throttledCallbacks++
}, 1000)()
expect(throttledCallbacks).to.equal(1)
})

it('executes the final callback after the elimit', async () => {
const throttle = createThrottleFn(100)
let throttledCallbacks = 0
throttle(() => {
throttledCallbacks++
}, 100)()
await new Promise((resolve) => setTimeout(resolve, 250))
expect(throttledCallbacks).to.equal(2)
})

it('does not execute the final if the timeouts were cleared', async () => {
const throttle = createThrottleFn(100)
let throttledCallbacks = 0
const fn = throttle(() => {
throttledCallbacks++
}, 100)
fn()
fn.clear()
await new Promise((resolve) => setTimeout(resolve, 250))
expect(throttledCallbacks).to.equal(1)
})

it('throttles callbacks according to given limit', async () => {
const throttle = createThrottleFn()
const fn = throttle(() => {
throttledCallbacks++
}, 500)
let throttledCallbacks = 0
for (let i = 0, n = 10; i < n; i++) {
fn()
await new Promise((resolve) => setTimeout(resolve, 30))
}
await new Promise((resolve) => setTimeout(resolve, 750))
expect(throttledCallbacks).to.equal(2)
})
})

0 comments on commit 558ed67

Please sign in to comment.