ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

VueUse 的 useDebounceFn:Vue 3 中的函数防抖利器(cancel / flush / isPending / maxWait 全解析)

VueUse 的 useDebounceFn:Vue 3 中的函数防抖利器(cancel / flush / isPending / maxWait 全解析) 前端【免费下载链接】vueuseCollection of essential Vue Composition Utilities for Vue 3项目地址https://gitcode.com/gh_mirrors/vu/vueuse点击查看免费下载useDebounceFn是 VueUsevueuse/core与vueuse/shared均会导出提供的一个函数防抖组合式工具它接收一个普通函数与延迟毫秒数返回一个防抖化的新函数并额外暴露cancel、flush、isPending等控制能力。本篇文章基于 VueUse 仓库中的 useDebounceFn 官方文档 展开结合 useDebounceFn 源码、底层 filters 实现 与 单元测试带你完整掌握它的用法、参数、返回值语义与底层原理可直接用于搜索、表单提交、窗口事件等真实场景。useDebounceFn 是什么防抖Debounce的思想是连续触发时只保留最后一次。官方文档用了一个很形象的比喻——防抖是一个超载的服务员只要你不停地提问你的请求就会被忽略直到你停下来给它一点时间思考你最新的问题。对应到前端场景用户持续输入、窗口持续 resize 时事件会高频触发防抖让真正要执行的逻辑等用户停下来或超过最大等待时间之后再执行避免无意义的重复计算与请求。useDebounceFn对任意函数做防抖包装是最底层的函数级防抖工具。VueUse 中其他高频场景工具如 refDebounced 的 ref 更新、useScroll 的滚动结束回调内部都复用了它。基本用法import { useDebounceFn, useEventListener } from vueuse/core const debouncedFn useDebounceFn(() { // do something }, 1000) useEventListener(window, resize, debouncedFn)把返回的debouncedFn直接交给事件监听器即可窗口 resize 在 1 秒内被连续触发时内部函数只会执行一次以最后一次触发为起点计时。参数详解从 index.ts 可以看到完整签名export function useDebounceFnT extends FunctionArgs( fn: T, ms: MaybeRefOrGetternumber 200, options: DebounceFilterOptions {}, ): UseDebounceFnReturnT参数类型默认值说明fn任意函数必填要被防抖执行的函数参数与返回值类型会完整透传msMaybeRefOrGetternumber200防抖延迟毫秒数。支持 ref / getter延迟可响应式动态调整对事件回调而言100 或 250甚至更高通常是实用取值options.maxWaitMaybeRefOrGetternumber未设置最大等待时间毫秒超过该时长即使仍在连续触发也会强制执行options.rejectOnCancelbooleanfalse取消时是否让对应 Promise 拒绝rejectms之所以声明为MaybeRefOrGetternumber是因为底层debounceFilter在每次触发时通过toValue(ms)取实时值见 filters.ts这意味着你可以用ref动态调整防抖延迟而无需重建函数。测试用例 should debounce with ref 验证了这一点。第 3 个参数maxWait最大等待时间该选项对标 lodash 的debounceimport { useDebounceFn, useEventListener } from vueuse/core // 如果因为持续输入而在 5000ms 内一直没有停歇 // 函数无论如何都会被调用一次 const debouncedFn useDebounceFn(() { // do something }, 1000, { maxWait: 5000 }) useEventListener(window, resize, debouncedFn)maxWait保证函数在连续高频触发下也不会被无限推迟——典型的兜底场景是用户一直不停输入但服务端必须每隔一段时间收到一次查询。底层实现上filters.ts每次触发都会创建或复用一个maxTimer当maxDuration到达时它会清掉普通防抖定时器并立即执行最后一次调用然后把maxTimer重置为undefined以便下一轮重新计时。第 3 个参数rejectOnCancel取消时是否拒绝 Promise防抖函数调用后返回的是一个 Promise。默认情况下rejectOnCancel: false如果调用被取消该 Promise不会被拒绝而是以undefined被 resolve——避免开发者不需要返回值时被未处理的 Promise 拒绝打扰。import { useDebounceFn } from vueuse/core const debouncedFn useDebounceFn(() response, 1000, { rejectOnCancel: true }) debouncedFn() .then((value) { // do something }) .catch(() { // do something when canceled }) // 再次调用会取消上一次请求且上一次的 Promise 会被 reject setTimeout(debouncedFn, 500)需要捕获取消事件时显式指定rejectOnCancel: true。这一行为在 should cancel and reject when rejectOnCancel is true 与 should cancel and resolve with undefined when rejectOnCancel is false 两个测试中得到了完整验证。返回值可 Promise 化的防抖函数useDebounceFn的返回类型是CancelablePromisifyFnT定义见 filters.ts即一个被 Promise 化promisify且可取消的函数附带cancel、flush与只读的isPending三个附加成员。由于返回的防抖函数本身就是 Promise 化的你可以用.then()或async/await拿到原函数的返回值import { useDebounceFn } from vueuse/core const debouncedFn useDebounceFn(() response, 1000) debouncedFn().then((value) { console.log(value) // response }) // 或使用 async/await async function doRequest() { const value await debouncedFn() console.log(value) // response }这一能力的实现位于 createFilterWrapper它把原始函数调用包进new Promise并将过滤器暴露的cancel、flush、isPending通过Object.assign挂到包装函数上同时保留原函数的this与参数列表fn.apply(this, args)因此方法也能被安全地防抖。cancel取消待执行调用import { useDebounceFn } from vueuse/core const debouncedFn useDebounceFn(() { // do something }, 1000) debouncedFn() // 在它真正执行前取消 debouncedFn.cancel()cancel()会清掉普通防抖定时器与maxTimer把isPending置为false并按rejectOnCancel决定 resolve 还是 reject 挂起的 Promise见 filters.ts。适用场景组件卸载时、用户输入上下文改变时需要阻止防抖函数迟到执行。取消后再次调用仍可正常工作测试 should allow calling after cancel 验证了这一点且无待执行任务时调用cancel()是安全的空操作should be a no-op when cancel is called with nothing pending。isPending待执行状态import { useDebounceFn } from vueuse/core const debouncedFn useDebounceFn(() { // do something }, 1000) debouncedFn() console.log(debouncedFn.isPending.value) // true // 防抖时间过后或调用 cancel 之后 console.log(debouncedFn.isPending.value) // falseisPending是一个只读 ref底层由shallowReadonly(shallowRef(false))提供见 filters.ts在调用触发时变为true在超时执行、flush或cancel后回到false。它非常适合驱动加载指示器或在等待期间禁用 UI 元素。注意一个细节当ms为0时函数立即同步执行isPending不会进入true状态见测试 should set pending to false when duration is 0。flush立即执行待调用import { useDebounceFn } from vueuse/core const debouncedFn useDebounceFn(() { // do something }, 1000) debouncedFn() // 不等待防抖时间立即执行挂起的调用 debouncedFn.flush()flush()用于确保防抖函数马上执行典型场景离开页面之前收集最终状态、提交表单之前确保最后一次编辑已被处理。底层实现filters.ts只在_pending.value true时生效它会用原生clearTimeout清掉两个定时器刻意不触发lastRejector因为要通过lastResolve正常 resolve同步调用lastInvoker()并返回其结果对应的 Promise。当没有待执行调用时flush()是空操作测试 should be a no-op when flush is called with nothing pending执行后也不会产生多余的定时器回调should flush with maxWait timer active。源码级原理debounceFilter createFilterWrapperuseDebounceFn的实现极其简洁只有一行核心逻辑见 index.tsreturn createFilterWrapper(debounceFilter(ms, options), fn)整个机制由utils/filters.ts中的两个基础件组成它们同样支撑着useThrottleFn、useTimeoutFn等一系列工具debounceFilter(ms, options)返回一个带cancel/flush/isPending的可取消事件过滤器。内部维护两个定时器——普通防抖定时器timer与最大等待定时器maxTimer两者相互清除普通定时器触发时清掉maxTimermaxTimer触发时清掉普通定时器从而在防抖与限时兜底之间取得平衡filters.ts。createFilterWrapper(filter, fn)把过滤器与原始函数组合成 Promise 化的包装函数负责this绑定、参数透传、Promise 的 resolve/reject以及把过滤器的控制成员挂载到包装函数上filters.ts。关于类型UseDebounceFnReturnT直接复用了CancelablePromisifyFnT见 index.ts其PromisifyFnT保证返回类型保持PromiseAwaitedReturnTypeT定义见 types.ts即使原函数返回 Promise 也能被正确展平。实际场景示例场景一输入搜索防抖import { ref } from vue import { useDebounceFn } from vueuse/core const keyword ref() const search useDebounceFn(() { // 调用搜索接口 console.log(search for:, keyword.value) }, 300, { maxWait: 3000 }) // 在模板或 watch 中随输入调用 search()maxWait: 3000保证即使输入从未停歇服务端请求也至少每 3 秒发出一次。场景二配合 isPending 展示加载状态const loading computed(() debouncedFn.isPending.value) // 模板中div v-ifloading搜索中.../div场景三表单提交前 flushfunction handleSubmit() { debouncedFn.flush() // 确保最后一次编辑已生效 // 然后提交表单 }与 useThrottleFn 的取舍useDebounceFn的文档在 frontmatter 中标注了related: useThrottleFn两者是 VueUse 中处理高频调用的姊妹工具防抖debounce连续触发只执行最后一次适合等用户停手再干活的场景如输入联想、窗口 resize 后的重绘。节流throttle固定时间间隔内最多执行一次适合必须持续响应但不能太频繁的场景如滚动监听、拖拽坐标更新。选型核心在于你希望最后一次一定执行还是过程中也要有节奏地执行。小结useDebounceFn(fn, ms, options)返回的防抖函数具备三类能力Promise 化可用.then/await取返回值、可取消cancel配合rejectOnCancel捕获取消、可立即执行flush与可观测状态isPending。再加上ms的响应式支持和maxWait兜底足以覆盖绝大多数前端防抖需求。其底层由 debounceFilter 与 createFilterWrapper 组成这也是整个 VueUse 事件过滤器体系Event Filters的通用基石感兴趣的读者可以从 过滤器指南 继续深入了解。赞分享前端【免费下载链接】vueuseCollection of essential Vue Composition Utilities for Vue 3项目地址https://gitcode.com/gh_mirrors/vu/vueuse点击查看免费下载相关推荐python-sdk 测试质量规范全解析从行为命名到确定性的工程实践python sdk 测试质量规范全解析从行为命名到确定性的工程实践 在 Model Context ProtocolMCPPython SDK即 py前端VueUse useDebounceFn 完整实战指南在 airi 中实现函数防抖VueUse useDebounceFn 完整实战指南在 airi 中实现函数防抖 导读 useDebounceFn 是 VueUse 提供的一个工具型组合式AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染VueUse useSortedVue 3 中的响应式数组排序组合式函数VueUse useSortedVue 3 中的响应式数组排序组合式函数 useSorted 是 VueUse 在 vueuse/core 中提供的数组工具前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表