Skip to content

debounce

Create a debounced function that delays execution until calls stop for a period of time.

Basic Usage

typescript
import { debounce } from 'radash'

const debouncedSearch = debounce(async (query: string) => {
  const response = await fetch(`/api/search?q=${query}`)
  return response.json()
}, 300)

// When user types, search only executes after stopping input for 300ms
debouncedSearch('hello')
debouncedSearch('hello world')
debouncedSearch('hello world example')
// Only the last call will execute

Syntax

typescript
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number,
  options?: {
    immediate?: boolean
  }
): (...args: Parameters<T>) => void

Parameters

  • fn (function): The function to debounce
  • delay (number): Delay time in milliseconds
  • options (object, optional): Configuration options
    • immediate (boolean, optional): Whether to execute the first call immediately, defaults to false

Return Value

Returns a debounced function.

Examples

Basic Debouncing

typescript
import { debounce } from 'radash'

const debouncedLog = debounce((message: string) => {
  console.log('Debounced:', message)
}, 500)

// Multiple rapid calls
debouncedLog('hello')
debouncedLog('hello world')
debouncedLog('hello world example')
// Only the last call will execute after 500ms

Search Input Debouncing

typescript
import { debounce } from 'radash'

const searchInput = document.getElementById('search') as HTMLInputElement

const debouncedSearch = debounce(async (query: string) => {
  if (query.length < 2) return
  
  const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
  const results = await response.json()
  
  displayResults(results)
}, 300)

searchInput.addEventListener('input', (e) => {
  const query = (e.target as HTMLInputElement).value
  debouncedSearch(query)
})

function displayResults(results: any[]) {
  // Display search results
  console.log('Search results:', results)
}

Window Resize Debouncing

typescript
import { debounce } from 'radash'

const debouncedResize = debounce(() => {
  console.log('Window resized to:', window.innerWidth, 'x', window.innerHeight)
  // Recalculate layout
  recalculateLayout()
}, 250)

window.addEventListener('resize', debouncedResize)

function recalculateLayout() {
  // Recalculate page layout
  console.log('Layout recalculated')
}

Form Submit Debouncing

typescript
import { debounce } from 'radash'

const debouncedSubmit = debounce(async (formData: FormData) => {
  try {
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData
    })
    
    if (!response.ok) {
      throw new Error('Submit failed')
    }
    
    const result = await response.json()
    console.log('Form submitted successfully:', result)
  } catch (error) {
    console.error('Submit error:', error)
  }
}, 1000)

const form = document.getElementById('myForm') as HTMLFormElement
form.addEventListener('submit', (e) => {
  e.preventDefault()
  const formData = new FormData(form)
  debouncedSubmit(formData)
})

Immediate Execution Mode

typescript
import { debounce } from 'radash'

const debouncedFunction = debounce((value: string) => {
  console.log('Executed with:', value)
}, 500, { immediate: true })

// First call executes immediately
debouncedFunction('first') // Executes immediately
debouncedFunction('second') // Executes after 500ms delay
debouncedFunction('third') // Executes after 500ms delay

API Call Debouncing

typescript
import { debounce } from 'radash'

const debouncedApiCall = debounce(async (params: any) => {
  const response = await fetch('/api/data', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(params)
  })
  
  return response.json()
}, 300)

// Call during user actions
async function handleUserAction() {
  const params = { action: 'update', data: { /* ... */ } }
  const result = await debouncedApiCall(params)
  console.log('API result:', result)
}

Scroll Event Debouncing

typescript
import { debounce } from 'radash'

const debouncedScroll = debounce(() => {
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop
  console.log('Scrolled to:', scrollTop)
  
  // Update scroll indicator
  updateScrollIndicator(scrollTop)
}, 100)

window.addEventListener('scroll', debouncedScroll)

function updateScrollIndicator(scrollTop: number) {
  const indicator = document.getElementById('scroll-indicator')
  if (indicator) {
    indicator.style.width = `${(scrollTop / (document.body.scrollHeight - window.innerHeight)) * 100}%`
  }
}

Keyboard Event Debouncing

typescript
import { debounce } from 'radash'

const debouncedKeyPress = debounce((key: string) => {
  console.log('Key pressed:', key)
  // Process keyboard input
  processKeyInput(key)
}, 200)

document.addEventListener('keydown', (e) => {
  debouncedKeyPress(e.key)
})

function processKeyInput(key: string) {
  // Process keyboard input logic
  console.log('Processing key:', key)
}

Mouse Move Debouncing

typescript
import { debounce } from 'radash'

const debouncedMouseMove = debounce((x: number, y: number) => {
  console.log('Mouse position:', x, y)
  // Update mouse position display
  updateMousePosition(x, y)
}, 50)

document.addEventListener('mousemove', (e) => {
  debouncedMouseMove(e.clientX, e.clientY)
})

function updateMousePosition(x: number, y: number) {
  const positionElement = document.getElementById('mouse-position')
  if (positionElement) {
    positionElement.textContent = `X: ${x}, Y: ${y}`
  }
}

Complex Parameter Debouncing

typescript
import { debounce } from 'radash'

interface SearchParams {
  query: string
  filters: Record<string, any>
  page: number
}

const debouncedSearch = debounce(async (params: SearchParams) => {
  const queryString = new URLSearchParams({
    q: params.query,
    page: params.page.toString(),
    ...params.filters
  }).toString()
  
  const response = await fetch(`/api/search?${queryString}`)
  const results = await response.json()
  
  return {
    results,
    total: results.length,
    page: params.page
  }
}, 500)

// Use debounced search
async function performSearch() {
  const params: SearchParams = {
    query: 'javascript',
    filters: { category: 'programming', sort: 'relevance' },
    page: 1
  }
  
  const result = await debouncedSearch(params)
  console.log('Search result:', result)
}

Cancel Debounced Function

typescript
import { debounce } from 'radash'

const debouncedFunction = debounce((message: string) => {
  console.log('Executed:', message)
}, 1000)

// Call function
debouncedFunction('hello')

// Cancel delayed execution
// Note: radash debounce doesn't directly support cancellation, but can be achieved by recreating the function
const cancelDebounce = () => {
  // Recreate debounced function to "cancel" previous calls
  const newDebouncedFunction = debounce((message: string) => {
    console.log('Executed:', message)
  }, 1000)
  
  return newDebouncedFunction
}

Multiple Debounced Functions

typescript
import { debounce } from 'radash'

// Create multiple debounced functions with different delays
const quickDebounce = debounce((action: string) => {
  console.log('Quick action:', action)
}, 100)

const mediumDebounce = debounce((action: string) => {
  console.log('Medium action:', action)
}, 500)

const slowDebounce = debounce((action: string) => {
  console.log('Slow action:', action)
}, 1000)

// Use different debounced functions
quickDebounce('fast')
mediumDebounce('normal')
slowDebounce('slow')

Conditional Debouncing

typescript
import { debounce } from 'radash'

const conditionalDebounce = debounce((value: string, shouldExecute: boolean) => {
  if (shouldExecute) {
    console.log('Executing with value:', value)
    // Execute actual logic
    processValue(value)
  }
}, 300)

function processValue(value: string) {
  // Logic to process value
  console.log('Processing:', value)
}

// Decide whether to execute based on condition
conditionalDebounce('test', true)
conditionalDebounce('skip', false)
conditionalDebounce('execute', true)

Notes

  1. Delay time: Choose appropriate delay time, too short may be ineffective, too long affects user experience
  2. Memory leaks: Debounced functions maintain references to original functions
  3. Immediate execution: Use immediate option to execute first call immediately
  4. Async functions: Debounced functions can wrap async functions
  5. Parameter passing: Debounced functions pass all parameters to original function

Differences from Other Methods

  • throttle(): Limits execution frequency, debounce delays execution
  • debounce(): Waits for calls to stop before executing
  • Manual implementation: Requires more code and error handling

Practical Application Scenarios

  1. Search input: Prevent frequent API calls
  2. Window resize: Optimize layout recalculation
  3. Form submission: Prevent duplicate submissions
  4. Scroll events: Optimize scroll handling
  5. Keyboard events: Reduce keyboard event processing frequency

Released under the MIT License.