You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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);

这段代码的执行逻辑:

  1. 0秒触发"0",加入队列并启动1秒延迟
  2. 1秒后延迟结束,执行"0"的异步任务并标记为正在执行
  3. 2秒触发"2000",加入队列并清除当前延迟(此时因正在执行"0",不会立即执行)
  4. 4秒触发"4000",加入队列并清除当前延迟
  5. 5秒时"0"执行完成,解除执行标记并启动1秒延迟
  6. 6秒时检查队列,取出最后加入的"4000"执行,忽略中间的"2000"
  7. 11秒时"4000"执行完成,队列清空,流程结束

最终输出会符合期望结果。

部分第三方工具库(如p-debounce)也提供支持异步函数的防抖能力,核心逻辑和上述自定义实现类似。

内容的提问来源于stack exchange,提问作者Dmitry Klochkov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 02:05:24