如何实现指定时长内函数仅执行一次?lodash debounce使用问题
问题原因与实现方案
你的代码和选型存在两个核心问题,导致效果不符合预期:
- 工具选型错误:
lodash.debounce是防抖函数,逻辑为触发事件后等待指定毫秒数再执行,等待期间重复触发会重置等待计时,适合搜索联想、窗口resize回调这类场景,完全不符合你「指定秒数内不重复执行」的需求,这类固定时间窗口内最多执行一次的逻辑应该用节流lodash.throttle实现。 - 常见使用误区:如果你的防抖/节流函数不是在模块全局/外层作用域只初始化一次,而是写在业务请求函数内部每次调用都重新创建实例,会因为每个实例没有共享上次执行的时间标记,完全失去限频效果。另外你贴的示例代码里API请求部分本身存在语法错误,也会导致执行异常。
基础限频实现(满足1秒内不重复执行需求)
直接替换为节流函数即可,注意配置参数让第一次触发立刻执行,窗口结束后不额外补执行:
import { throttle } from 'lodash'; // 注意:这个节流函数要提在模块外层,只初始化一次,不要写在业务请求函数内部 const refreshToken = throttle(() => { // 替换为你实际的token刷新请求逻辑 api.request({ url: '/auth/refresh', method: 'POST', data: { refreshToken: localStorage.getItem('refreshToken') } }); }, 1000, { leading: true, // 第一次触发立刻执行 trailing: false // 1秒窗口结束后不补执行错过的调用 }); // 每次业务请求需要刷新token时直接调用即可 refreshToken();
更严谨的token刷新场景实现
对于token刷新这类鉴权场景,单纯节流还存在并发请求触发重复调用的风险,可以加状态标记做更稳妥的控制:
let isRefreshing = false; let pendingRefresh = null; let lastRefreshTime = 0; async function safeRefreshToken() { // 已有正在进行的刷新请求,直接返回当前请求的Promise,避免重复发起 if (isRefreshing) return pendingRefresh; // 距离上次刷新不足1秒,直接跳过 if (Date.now() - lastRefreshTime < 1000) return; isRefreshing = true; lastRefreshTime = Date.now(); pendingRefresh = api.request({ url: '/auth/refresh', method: 'POST', data: { refreshToken: localStorage.getItem('refreshToken') } }).finally(() => { isRefreshing = false; pendingRefresh = null; }); return pendingRefresh; }
补充说明:如果你坚持要用debounce实现,需要把配置改成
{ leading: true, trailing: false },效果和节流一致,但从语义和维护角度不推荐这么做。
内容的提问来源于stack exchange,提问作者Dylan L.
相关产品推荐
相关产品推荐

