All files / function throttle.ts

100% Statements 27/27
57.14% Branches 4/7
100% Functions 4/4
100% Lines 27/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67                                          1x 2x   2x 1x 1x     1x   1x 1x 1x 1x 1x 1x 1x       1x         1x 1x   1x 1x   1x 1x 1x   1x 1x   1x 1x 1x   1x      
import { isUndefined } from '../is'
 
/**
 * Creates a throttled function that only invokes `func` at most once per
 * every `wait` milliseconds. The throttled function comes with a `cancel`
 * method to cancel delayed `func` invocations.
 *
 * @param func The function to throttle
 * @param wait The number of milliseconds to throttle invocations to
 * @returns Returns the new throttled function
 *
 * {@link https://lodash.com/docs#throttle}
 */
export function throttle<T extends (...args: any[]) => any>(
  func: T,
  wait: number = 0,
): (...args: Parameters<T>) => void {
  let timeoutId: ReturnType<typeof setTimeout> | undefined
  let lastArgs: Parameters<T> | undefined
  let lastCallTime: number | undefined
 
  return function throttled(this: any, ...args: Parameters<T>): void {
    let time = Date.now()
 
    if (isUndefined(lastCallTime)) {
      lastCallTime = time
      func.apply(this, args)
    }
    else {
      clearTimeout(timeoutId)
 
      timeoutId = setTimeout(() => {
        time = Date.now()
        Eif ((time - lastCallTime!) >= wait) {
          func.apply(this, lastArgs!)
          lastCallTime = time
          timeoutId = undefined
          lastArgs = undefined
        }
      }, wait)
 
      lastArgs = args
    }
  }
}
 
Eif (import.meta.vitest) {
  const { test, expect, vi } = import.meta.vitest
 
  test('throttle', async () => {
    vi.useFakeTimers()
 
    const fn = vi.fn()
    const throttled = throttle(fn, 100)
    expect(fn).not.toHaveBeenCalled()
 
    throttled()
    expect(fn).toHaveBeenCalledTimes(1)
 
    throttled()
    vi.advanceTimersByTime(100)
    expect(fn).toHaveBeenCalledTimes(2)
 
    vi.useRealTimers()
  })
}