Skip to content

时序控制 useLockFn / useDebounceFn / useThrottleFn ​

业务侧最高频的三类时序问题各给一个最小 hook:防重复提交(useLockFn)、防抖(useDebounceFn,停顿才算数)、节流(useThrottleFn,高频按节奏放行)。零依赖、作用域销毁自动清理(防抖 / 节流)。

useLockFn:提交防重 ​

执行期间(及可选反馈保持期)忽略后续调用,loading 直接绑定按钮——比手动 :loading 收敛在函数维度,多入口(按钮 + 回车)调用同一函数也只放行一次。

ts
const { run: submit, loading } = useLockFn(async (values) => {
  await api.save(values)
  ElMessage.success('已提交')
})
// 模板:<el-button :loading="loading" @click="submit(form)">提交</el-button>
连点按钮或输入框内回车,1.5s 内只发一次。
连点按钮或输入框内回车,1.5s 请求期内只放行一次。
已支付:¥0(连点不会多扣)
支付确认防重:确认弹窗取消不触发支付,支付期间按钮锁定杜绝重复扣款。
已完成:—;执行期间再次点击不会启动第二批。
批量审批逐条 await,整体流程锁定,避免两批并发交叉执行。
已保存 0 次;接口 0.6s 即回,但按钮锁到 2.1s 才放开。
{ lockDuring: 1500 } 成功后额外锁 1.5s:成功提示期防误触二次提交。

useDebounceFn:防抖(trailing) ​

最后一次调用后 delay ms 触发一次;cancel 取消等待、flush 立即触发等待中的值(「立即应用」按钮场景)。

ts
const { run: search, cancel, flush, pending } = useDebounceFn((kw: string) => {
  void api.suggest(kw)
}, 400)

请求 0 次(快速连续输入只在停顿后发 1 次)

搜索联想:快速连续输入只在停顿后发一次请求(请求计数对比)。
价格 ≤ 100 元

已按 ≤100 元查询(共 0 次);flush 可不等停顿立即触发等待中的值。

筛选联动:滑块拖动过程不查,停 300ms 才触发;flush 演示立即应用等待中的值。

useThrottleFn:节流(leading + trailing) ​

interval 内至多触发一次:首次立即响应,间隔内的末次参数在间隔尾补发(最后一次调用不丢)。

ts
const { run: onScroll } = useThrottleFn(() => {
  if (nearBottom()) loadMore()
}, 500)
条目 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

触发检查 0 次 / 加载 0 次(滚动到底部连续触发也被限到 500ms 一次)

滚动加载:scroll 高频事件按 500ms 节奏触发到底检查。
窗口:0 × 0已按节流更新 0 次——拖拽浏览器窗口边缘试试。
窗口 resize:拖拽窗口边缘按 400ms 节奏更新尺寸。

API ​

useLockFn(fn, options?) ​

成员类型说明
run(...args) => Promise | undefined锁定期间调用返回 undefined(不排队不重入)
loadingRef<boolean>执行中(含 lockDuring 保持期),绑定按钮 loading / disabled
选项类型默认说明
lockDuringnumber0成功/失败后继续锁定 ms(反馈期防误触)

useDebounceFn(fn, delay = 300) ​

成员类型说明
run(...args) => void停止调用 delay ms 后触发一次
cancel() => void取消未触发的等待
flush() => void立即触发等待中的调用(无等待不动作)
pending() => boolean是否有待触发的等待

useThrottleFn(fn, interval = 300) ​

成员类型说明
run(...args) => void间隔内首次立即触发,末次参数间隔尾补发
cancel() => void取消待补发的末次调用
pending() => boolean是否处于节流间隔内

选型 ​

  • 会写库 / 会付钱 / 会发消息的动作 → useLockFn(一次都不许多);
  • 等用户停(联想、联动查询、草稿保存)→ useDebounceFn;
  • 高频事件按节奏(scroll / resize / mousemove)→ useThrottleFn。