Skip to content

throttle

创建一个节流函数,限制函数的执行频率。

基础用法

typescript
import { throttle } from 'radash'

const throttledScroll = throttle(() => {
  console.log('Scroll event handled')
}, 100)

window.addEventListener('scroll', throttledScroll)
// 滚动时,函数最多每100ms执行一次

语法

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

参数

  • fn (function): 要节流的函数
  • delay (number): 延迟时间(毫秒)
  • options (object, 可选): 配置选项
    • leading (boolean, 可选): 是否在开始时执行,默认为true
    • trailing (boolean, 可选): 是否在结束时执行,默认为true

返回值

返回一个节流后的函数。

示例

基本节流

typescript
import { throttle } from 'radash'

const throttledLog = throttle((message: string) => {
  console.log('Throttled:', message)
}, 1000)

// 快速连续调用
throttledLog('hello')
throttledLog('world')
throttledLog('example')
// 只有第一次调用会立即执行,后续调用会被节流

滚动事件节流

typescript
import { throttle } from 'radash'

const throttledScroll = throttle(() => {
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop
  console.log('Scroll position:', scrollTop)
  
  // 更新滚动指示器
  updateScrollIndicator(scrollTop)
}, 100)

window.addEventListener('scroll', throttledScroll)

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

窗口大小调整节流

typescript
import { throttle } from 'radash'

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

window.addEventListener('resize', throttledResize)

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

鼠标移动节流

typescript
import { throttle } from 'radash'

const throttledMouseMove = throttle((x: number, y: number) => {
  console.log('Mouse position:', x, y)
  
  // 更新鼠标位置显示
  updateMousePosition(x, y)
}, 50)

document.addEventListener('mousemove', (e) => {
  throttledMouseMove(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 { throttle } from 'radash'

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

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

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

搜索输入节流

typescript
import { throttle } from 'radash'

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

const throttledSearch = throttle(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
  throttledSearch(query)
})

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

只执行开始时的节流

typescript
import { throttle } from 'radash'

const leadingThrottle = throttle((action: string) => {
  console.log('Action:', action)
}, 1000, { leading: true, trailing: false })

// 第一次调用立即执行
leadingThrottle('start')
leadingThrottle('middle')
leadingThrottle('end')
// 只有第一次调用会执行,后续调用被忽略

只执行结束时的节流

typescript
import { throttle } from 'radash'

const trailingThrottle = throttle((action: string) => {
  console.log('Action:', action)
}, 1000, { leading: false, trailing: true })

// 第一次调用不会立即执行
trailingThrottle('start')
trailingThrottle('middle')
trailingThrottle('end')
// 只有最后一次调用会在延迟后执行

API调用节流

typescript
import { throttle } from 'radash'

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

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

复杂参数节流

typescript
import { throttle } from 'radash'

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

const throttledSearch = throttle(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 throttledSearch(params)
  console.log('Search result:', result)
}

表单验证节流

typescript
import { throttle } from 'radash'

const emailInput = document.getElementById('email') as HTMLInputElement

const throttledValidation = throttle(async (email: string) => {
  if (!email.includes('@')) return
  
  const response = await fetch('/api/validate-email', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email })
  })
  
  const result = await response.json()
  
  if (result.valid) {
    emailInput.classList.remove('error')
    emailInput.classList.add('valid')
  } else {
    emailInput.classList.remove('valid')
    emailInput.classList.add('error')
  }
}, 300)

emailInput.addEventListener('input', (e) => {
  const email = (e.target as HTMLInputElement).value
  throttledValidation(email)
})

多个节流函数

typescript
import { throttle } from 'radash'

// 创建多个不同延迟的节流函数
const quickThrottle = throttle((action: string) => {
  console.log('Quick action:', action)
}, 100)

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

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

// 使用不同的节流函数
quickThrottle('fast')
mediumThrottle('normal')
slowThrottle('slow')

条件节流

typescript
import { throttle } from 'radash'

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

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

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

性能监控节流

typescript
import { throttle } from 'radash'

const throttledPerformanceLog = throttle(() => {
  const memory = performance.memory
  console.log('Memory usage:', {
    used: Math.round(memory.usedJSHeapSize / 1024 / 1024) + 'MB',
    total: Math.round(memory.totalJSHeapSize / 1024 / 1024) + 'MB',
    limit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024) + 'MB'
  })
}, 5000) // 每5秒最多执行一次

// 定期监控性能
setInterval(throttledPerformanceLog, 1000)

注意事项

  1. 延迟时间: 选择合适的延迟时间,太短可能无效,太长影响响应性
  2. 内存泄漏: 节流函数会保持对原函数的引用
  3. leading/trailing: 控制函数在开始和结束时是否执行
  4. 异步函数: 节流函数可以包装异步函数
  5. 参数传递: 节流函数会传递所有参数给原函数

与其他方法的区别

  • debounce(): 延迟执行直到停止调用,节流是限制执行频率
  • throttle(): 限制执行频率,确保函数按固定间隔执行
  • 手动实现: 需要更多代码和错误处理

实际应用场景

  1. 滚动事件: 优化滚动处理性能
  2. 窗口调整: 限制布局重新计算频率
  3. 鼠标移动: 减少鼠标事件处理频率
  4. 键盘事件: 限制键盘事件处理
  5. API调用: 防止频繁的API请求

Released under the MIT License.