Appearance
throttle 节流函数
在持续触发场景(滚动、窗口尺寸变化、鼠标移动等)中,节流可将频繁触发限制为固定时间窗口内最多执行一次,避免过度计算或渲染。
安装与引入
按需导入(推荐)
ts
import { throttle } from '@cuixingjian/cui-utils'子路径导入
ts
import { throttle } from '@cuixingjian/cui-utils/throttle'效果演示
基础用法
快速点击按钮,每 1000ms 最多执行一次。
使用代码
基础节流:
ts
import { throttle } from '@cuixingjian/cui-utils'
const onScroll = () => {
console.log('处理滚动逻辑')
}
// 每 200ms 最多执行一次
const onScrollThrottled = throttle(onScroll, 200)
window.addEventListener('scroll', onScrollThrottled)立即执行模式:
ts
import { throttle } from '@cuixingjian/cui-utils'
const resize = () => {
console.log('处理窗口尺寸变化')
}
const resizeThrottled = throttle(resize, 300, { immediate: true })
window.addEventListener('resize', resizeThrottled)取消与立即触发:
ts
import { throttle } from '@cuixingjian/cui-utils'
const handler = throttle(() => {
console.log('执行处理')
}, 300)
// 取消等待中的尾触发
handler.cancel()
// 立即执行最后一次的调用(如果存在)
handler.flush()API 说明
函数签名
ts
function throttle<T extends (...args: any[]) => any>(
fn: T,
wait?: number,
options?: ThrottleOptions
): ThrottledFn<T>参数
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| fn | (...args: any[]) => any | — | 需要节流的函数 |
| wait | number | 200 | 时间窗口(毫秒) |
| options | ThrottleOptions | {} | 配置选项 |
ThrottleOptions
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| immediate | boolean | false | 是否在首次触发时立即执行(leading) |
返回值
返回一个节流函数 ThrottledFn<T>,具有以下方法:
| 方法 | 类型 | 说明 |
|---|---|---|
| cancel | () => void | 取消等待中的尾触发 |
| flush | () => void | 立即执行最后一次的调用(如果存在) |
注意事项
基本规则
- 在组件卸载前如仍有节流等待中的尾触发,建议调用
cancel()进行清理 - 节流函数会保留
this上下文和参数
immediate 模式说明
immediate: true表示领先(leading)触发,首次立即执行- 尾触发仍可能在窗口末尾执行一次
- 适合需要即时响应的场景
典型场景
- 滚动事件监听:限制滚动处理频率,提升性能
- 窗口尺寸变化:控制 resize 事件处理频率
- 鼠标移动追踪:降低 mousemove 事件处理频率
- 按钮连续点击:防止短时间内重复提交
源码
展开查看
ts
// 源码来自 @cuixingjian/cui-utils/throttle
export interface ThrottleOptions {
immediate?: boolean
}
export interface ThrottledFn<T extends (...args: any[]) => any> {
(...args: Parameters<T>): void
cancel: () => void
flush: () => void
}
export function throttle<T extends (...args: any[]) => any>(
fn: T,
wait = 200,
options: ThrottleOptions = {}
): ThrottledFn<T> {
let timer: ReturnType<typeof setTimeout> | null = null
let lastInvokeTime = 0
let lastArgs: Parameters<T> | null = null
let lastThis: any = null
let trailingPending = false
const { immediate = false } = options
const invoke = () => {
if (lastArgs) {
fn.apply(lastThis, lastArgs)
lastArgs = null
lastThis = null
}
}
const throttled = function (this: any, ...args: Parameters<T>) {
const now = Date.now()
lastArgs = args
lastThis = this
if (immediate && (lastInvokeTime === 0 || now - lastInvokeTime >= wait)) {
fn.apply(this, args)
lastInvokeTime = now
trailingPending = false
if (!timer) {
timer = setTimeout(() => {
if (trailingPending) {
invoke()
lastInvokeTime = Date.now()
}
timer = null
trailingPending = false
}, wait)
}
return
}
trailingPending = true
if (!timer) {
const elapsed = lastInvokeTime ? now - lastInvokeTime : 0
const remaining = wait - elapsed
const delay = remaining > 0 ? remaining : wait
timer = setTimeout(() => {
invoke()
lastInvokeTime = Date.now()
timer = null
trailingPending = false
}, delay)
}
} as ThrottledFn<T>
throttled.cancel = () => {
if (timer) {
clearTimeout(timer)
timer = null
}
trailingPending = false
lastArgs = null
lastThis = null
}
throttled.flush = () => {
if (timer) {
clearTimeout(timer)
timer = null
}
if (trailingPending || lastArgs) {
invoke()
lastInvokeTime = Date.now()
trailingPending = false
}
}
return throttled
}