Skip to content

debounce

创建一个防抖函数,延迟执行直到停止调用一段时间。

基础用法

typescript
import { debounce } from 'radash'

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

// 用户输入时,只有在停止输入300ms后才会执行搜索
debouncedSearch('hello')
debouncedSearch('hello world')
debouncedSearch('hello world example')
// 只有最后一次调用会执行

语法

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

参数

  • fn (function): 要防抖的函数
  • delay (number): 延迟时间(毫秒)
  • options (object, 可选): 配置选项
    • immediate (boolean, 可选): 是否立即执行第一次调用,默认为false

返回值

返回一个防抖后的函数。

示例

基本防抖

typescript
import { debounce } from 'radash'

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

// 多次快速调用
debouncedLog('hello')
debouncedLog('hello world')
debouncedLog('hello world example')
// 只有最后一次调用会在500ms后执行

搜索输入防抖

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[]) {
  // 显示搜索结果
  console.log('Search results:', results)
}

窗口大小调整防抖

typescript
import { debounce } from 'radash'

const debouncedResize = debounce(() => {
  console.log('Window resized to:', window.innerWidth, 'x', window.innerHeight)
  // 重新计算布局
  recalculateLayout()
}, 250)

window.addEventListener('resize', debouncedResize)

function recalculateLayout() {
  // 重新计算页面布局
  console.log('Layout recalculated')
}

表单提交防抖

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)
})

立即执行模式

typescript
import { debounce } from 'radash'

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

// 第一次调用会立即执行
debouncedFunction('first') // 立即执行
debouncedFunction('second') // 延迟500ms后执行
debouncedFunction('third') // 延迟500ms后执行

API调用防抖

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)

// 在用户操作时调用
async function handleUserAction() {
  const params = { action: 'update', data: { /* ... */ } }
  const result = await debouncedApiCall(params)
  console.log('API result:', result)
}

滚动事件防抖

typescript
import { debounce } from 'radash'

const debouncedScroll = debounce(() => {
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop
  console.log('Scrolled to:', scrollTop)
  
  // 更新滚动指示器
  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}%`
  }
}

键盘事件防抖

typescript
import { debounce } from 'radash'

const debouncedKeyPress = debounce((key: string) => {
  console.log('Key pressed:', key)
  // 处理键盘输入
  processKeyInput(key)
}, 200)

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

function processKeyInput(key: string) {
  // 处理键盘输入逻辑
  console.log('Processing key:', key)
}

鼠标移动防抖

typescript
import { debounce } from 'radash'

const debouncedMouseMove = debounce((x: number, y: number) => {
  console.log('Mouse position:', x, y)
  // 更新鼠标位置显示
  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}`
  }
}

复杂参数防抖

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)

// 使用防抖搜索
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)
}

取消防抖函数

typescript
import { debounce } from 'radash'

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

// 调用函数
debouncedFunction('hello')

// 取消延迟执行
// 注意:radash的debounce不直接支持取消,但可以通过重新创建函数来实现
const cancelDebounce = () => {
  // 重新创建防抖函数来"取消"之前的调用
  const newDebouncedFunction = debounce((message: string) => {
    console.log('Executed:', message)
  }, 1000)
  
  return newDebouncedFunction
}

多个防抖函数

typescript
import { debounce } from 'radash'

// 创建多个不同延迟的防抖函数
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)

// 使用不同的防抖函数
quickDebounce('fast')
mediumDebounce('normal')
slowDebounce('slow')

条件防抖

typescript
import { debounce } from 'radash'

const conditionalDebounce = debounce((value: string, shouldExecute: boolean) => {
  if (shouldExecute) {
    console.log('Executing with value:', value)
    // 执行实际逻辑
    processValue(value)
  }
}, 300)

function processValue(value: string) {
  // 处理值的逻辑
  console.log('Processing:', value)
}

// 根据条件决定是否执行
conditionalDebounce('test', true)
conditionalDebounce('skip', false)
conditionalDebounce('execute', true)

注意事项

  1. 延迟时间: 选择合适的延迟时间,太短可能无效,太长影响用户体验
  2. 内存泄漏: 防抖函数会保持对原函数的引用
  3. 立即执行: 使用immediate选项可以立即执行第一次调用
  4. 异步函数: 防抖函数可以包装异步函数
  5. 参数传递: 防抖函数会传递所有参数给原函数

与其他方法的区别

  • throttle(): 限制执行频率,防抖是延迟执行
  • debounce(): 等待停止调用后执行
  • 手动实现: 需要更多代码和错误处理

实际应用场景

  1. 搜索输入: 防止频繁的API调用
  2. 窗口调整: 优化布局重新计算
  3. 表单提交: 防止重复提交
  4. 滚动事件: 优化滚动处理
  5. 键盘事件: 减少键盘事件处理频率

Released under the MIT License.