踩坑指南:VueUse useThrottleFn 为什么"不听话"?
当你满心欢喜地用 useThrottleFn 来节流函数,却发现它还在"偷偷"执行额外的调用时,恭喜你踩到了一个经典的坑!让我们来看看这个"调皮"的 trailing 参数是如何在 8.7.3 版本中"搞事情"的。🤡
🎯 问题现象:我的节流怎么"失效"了?
你是否遇到过这样的情况:
// 你以为这样写,函数只会在开始时执行一次
const save = useThrottleFn(saveData, 1000);
// 疯狂点击保存按钮
save(); // 执行 ✅
save(); // 不执行 ✅
save(); // 不执行 ✅
save(); // 不执行 ✅
// 1秒后...
// WTF?怎么又执行了一次?😱
如果你正在使用 VueUse 8.7.3 版本,那么恭喜你中奖了!这不是 bug,这是"特性"!🎊
🔍 真相大白:trailing 参数在作怪
useThrottleFn 是 VueUse 提供的节流函数工具,但它有个"贴心"的默认行为:在节流周期结束后,还会"善意"地帮你执行最后一次调用。
这就是为什么你的函数会在你以为已经结束的时候,突然又执行一次的原因!😅😅😅
基本语法
v13.8.0 版本 官网 Type Declarations
/**
* Throttle execution of a function. Especially useful for rate limiting
* execution of handlers on events like resize and scroll.
*
* @param fn A function to be executed after delay milliseconds. The `this` context and all arguments are passed through, as-is,
* to `callback` when the throttled-function is executed.
* @param ms A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) are most useful.
* (default value: 200)
*
* @param [trailing] if true, call fn again after the time is up (default value: false)
*
* @param [leading] if true, call fn on the leading edge of the ms timeout (default value: true)
*
* @param [rejectOnCancel] if true, reject the last call if it's been cancel (default value: false)
*
* @return A new, throttled, function.
*
* @__NO_SIDE_EFFECTS__
*/
export declare function useThrottleFn<T extends FunctionArgs>(
fn: T,
ms?: MaybeRefOrGetter<number>,
trailing?: boolean,
leading?: boolean,
rejectOnCancel?: boolean
): PromisifyFn<T>;
import { useThrottleFn } from "@vueuse/core";
const throttledFn = useThrottleFn(fn, ms, trailing, leading, rejectOnCancel);
🔧 参数详解
1. fn (必需)
- 类型:
(...args: any[]) => any - 描述: 需要进行节流处理的目标函数
2. ms (必需)
- 类型:
number - 描述: 节流间隔时间,单位毫秒
- 默认值: 无(必须指定)
3. trailing ⚠️ 罪魁祸首就是你!
- 类型:
boolean - 描述: 是否在节流周期结束后执行最后一次调用
- 8.7.3 版本默认值:
true🤡(这就是你踩坑的原因!) - 后续版本变更:
- v8.9.0 之前:
true(包括你用的 8.7.3) - v8.9.0 及之后:
false🎉(终于!!!)
- v8.9.0 之前:
🎭 8.7.3 版本的"惊喜"行为
// 8.7.3 版本:trailing 默认为 true
const throttledFn = useThrottleFn(saveData, 1000);
// 等价于:useThrottleFn(saveData, 1000, true, true)
// 你期望的行为 vs 实际行为:
点击(); // 立即执行 ✅ 期望 ✅ 实际
点击(); // 被忽略 ✅ 期望 ✅ 实际
点击(); // 被忽略 ✅ 期望 ✅ 实际
点击(); // 被忽略 ✅ 期望 ✅ 实际
// 1秒后...
// 什么都不发生 ✅ 期望
// 又执行了一次 😱 实际!trailing 的"杰作"
💡 解决方案:显式关闭 trailing
// 8.7.3 版本的正确用法:手动关闭 trailing
const throttledFn = useThrottleFn(saveData, 1000, false);
// 这样就只会在开始时执行,结束时不会再"加餐"
// 或者完整写法更清晰
const throttledFn = useThrottleFn(
saveData,
1000, // 间隔时间
false, // trailing: 关闭结束时执行
true // leading: 保持开始时执行
);
4. leading
- 类型:
boolean - 描述: 是否在节流周期开始时立即执行
- 默认值:
true
5. rejectOnCancel
- 类型:
boolean - 描述: 当节流函数被取消时,是否拒绝 Promise
- 默认值:
false
// 返回 Promise 的异步函数
async function asyncFunction() {
return "result";
}
const throttledAsync = useThrottleFn(asyncFunction, 1000, false, true, true);
// 使用示例
try {
const result = await throttledAsync();
console.log(result);
} catch (error) {
console.log("被取消:", error);
}
🎉 踩坑总结:如何避免被 useThrottleFn "背刺"
如果你正在使用 VueUse 8.7.3,记住这几个要点:
🤡 问题根源:trailing 参数默认为 true,会在节流周期结束后"偷偷"执行最后一次调用
🔧 快速修复:显式设置 trailing: false,告诉函数"适可而止"
📈 版本升级:如果可能,升级到 v8.9.0+ 享受更合理的默认行为
⚠️ 注意兼容:升级版本时要检查现有代码,避免行为反转
🏆 最佳实践(8.7.3 版本)
// ❌ 错误:会有"惊喜"的额外执行
const badThrottle = useThrottleFn(saveData, 1000);
// ✅ 正确:明确控制行为
const goodThrottle = useThrottleFn(saveData, 1000, false, true);
// ✅ 更清晰:参数含义一目了然
const clearThrottle = useThrottleFn(
saveData,
1000, // 间隔时间
false, // trailing: 不要在结束时"加餐"
true // leading: 开始时立即执行
);
📚 记忆口诀
八点七点三版本用,trailing 默认 true 坑
显式 false 来救场,节流才能按预期 🎵
记住:在 8.7.3 版本中,不指定 trailing 参数 = 给自己埋坑! 💣
想了解更多 VueUse 踩坑指南?关注我避免更多"惊喜"! 🕳️