如何用Lodash实现带异步等待的防抖函数并保证执行顺序?
能否用Lodash对异步函数实现带异步等待的防抖?
需求是让防抖处理的异步函数,不仅在指定延迟后执行,还需等待最近一次触发的异步函数执行完毕后,再运行后续符合条件的调用。
示例代码
import _ from "lodash" const debouncedFunc = _.debounce(async (input: string) => { return new Promise<void>(resolve => { console.log(`start ${input}`) setTimeout(() => { console.log(`finish ${input}`) resolve() }, 5000) }) }, 1000) setTimeout(() => debouncedFunc("0"), 0) setTimeout(() => debouncedFunc("2000"), 2000) setTimeout(() => debouncedFunc("4000"), 4000)
当前输出
start 0 start 2000 start 4000 finish 0 finish 2000 finish 4000
期望输出
start 0 finish 0 start 4000 finish 4000
解答
Lodash原生的_.debounce不支持这种行为,它的防抖逻辑仅基于触发的时间间隔,不会追踪异步函数的执行状态——只要延迟时间到,就会直接调用函数,不管上一次的异步操作是否完成。
要实现需求中的行为,需要自定义一个结合防抖和异步等待的函数,核心逻辑是:
- 维护等待队列,记录待执行的调用参数
- 无正在执行的异步任务时,检查队列并取出任务执行,执行完成后重新检查队列并重置防抖延迟
以下是TypeScript实现示例:
function debounceAsync<T extends (...args: any[]) => Promise<any>>( func: T, wait: number ) { let timeoutId: NodeJS.Timeout | null = null; let isExecuting = false; const queue: Parameters<T>[] = []; const execute = async () => { if (isExecuting || queue.length === 0) return; isExecuting = true; const args = queue.shift()!; try { await func(...args); } finally { isExecuting = false; // 执行完成后,检查队列并重启防抖计时 timeoutId = setTimeout(execute, wait); } }; return (...args: Parameters<T>) => { queue.push(args); if (timeoutId) clearTimeout(timeoutId); timeoutId = setTimeout(execute, wait); }; } // 使用示例 const debouncedAsyncFunc = debounceAsync(async (input: string) => { return new Promise<void>(resolve => { console.log(`start ${input}`); setTimeout(() => { console.log(`finish ${input}`); resolve(); }, 5000); }); }, 1000); setTimeout(() => debouncedAsyncFunc("0"), 0); setTimeout(() => debouncedAsyncFunc("2000"), 2000); setTimeout(() => debouncedAsyncFunc("4000"), 4000);
这段代码的执行逻辑:
- 0秒触发"0",加入队列并启动1秒延迟
- 1秒后延迟结束,执行"0"的异步任务并标记为正在执行
- 2秒触发"2000",加入队列并清除当前延迟(此时因正在执行"0",不会立即执行)
- 4秒触发"4000",加入队列并清除当前延迟
- 5秒时"0"执行完成,解除执行标记并启动1秒延迟
- 6秒时检查队列,取出最后加入的"4000"执行,忽略中间的"2000"
- 11秒时"4000"执行完成,队列清空,流程结束
最终输出会符合期望结果。
部分第三方工具库(如p-debounce)也提供支持异步函数的防抖能力,核心逻辑和上述自定义实现类似。
内容的提问来源于stack exchange,提问作者Dmitry Klochkov
相关产品推荐
相关产品推荐

