delphi - 如何在 Delphi 中编写 Debounce() 过程?

标签 delphi anonymous-methods

我想编写一个类似于 Javascript 中常见实现的去抖动程序。例如debounce function in Underscore.js

我认为它可能看起来像这样:

procedure Debounce(const TimeMS : integer; MyAnonymousProcedure : TProc);

可以这样使用:

begin
  Debounce(200, procedure
  begin
    //Do something here...
  end);
end;

可能的实现#1

Debounce() 过程将检查自调用目标方法以来已经过去了多长时间。如果目标方法调用了 X 次,则会延迟。

伪代码版本:

procedure Debounce(const TimeMS : integer; MyAnonymousProcedure : TProc);
var
  TimeSinceCalled : integer;
begin
  TimeSinceCalled := FindTimeSinceProcedureLastCalled(MyAnonymousProcedure);
  if TimeMS < TimeSinceCalled then
  begin
    // The procedure hasn't been called recently,
    SaveTimeOfProcedureCall(MyAnonymousProcedure); // so save the current time...
    MyAnonymousProcedure;                          //  ...and call the procedure.
  end else
  begin
    // The procedure has been called recently so we use a timer
    // to call the procedure in X milliseconds.
    // The timer is reset each time Debounce() is called
    // so procedures will only be called when the Debounce time-out has
    // be passed.
    GlobalTimer.Reset;
    GlobalTimer.CallProcedureIn(MyAnonymousProcedure, TimeMS);
  end;
end;

我面临的问题是我需要某种方法来识别目标过程。我的第一个想法是使用目标过程的方法地址作为ID。例如:
ID := Address(Foo); ID := Addr(Foo);
但这不适用于匿名方法,因为它们在我的测试中使用相同的地址。理想情况下,ID 应自动生成。有任何想法吗?

最佳答案

你说你所有的匿名程序的地址都是相同的,但这是不可能的。相反,我怀疑您正在尝试错误的值。你说你打电话Address ,但没有这样的功能。您可能是说 Addr ,与 @ 相同运算符(operator)。但是,这为您提供了 MyAnonymousProcedure 的地址。形式参数,而不是其中存储的地址。每次调用该函数时,参数很可能具有相同的地址。

您正在寻找一种识别不同过程引用的方法。引用文献本身就足够了。您可以使用 TDictionary<TProc, TDateTime>将过程映射到其上次调用时间。

危险在于,每次运行时,您都会调用 Debounce带有过程文字的函数,您最终可能会构造该过程对象的全新实例,因此它的地址将与任何先前构造的过程不同,即使它使用相同的代码和相同的捕获变量值。

JavaScript 版本也容易出现同样的问题,这就是为什么它根本不尝试识别该函数。相反,它返回一个包装传入函数的新函数。新函数添加了延迟行为。在 Delphi 中,它可以像这样工作:

function Debounce(Delay: TDateTime; Proc: TProc): TProc;
var
  LastCall: TDateTime;
begin
  LastCall := 0;
  Result := procedure
  begin
    if LastCall + Delay <= Now then
      Proc;
    LastCall := Now;
  end;
end;

这个版本的工作方式就像 immediate Underscore版本中的参数为true。这是最简单的情况,因为它不需要任何延迟执行的机制。但是,它表明您实际上并不需要一种区分不同过程引用的方法,而这正是您之前所坚持的。

关于delphi - 如何在 Delphi 中编写 Debounce() 过程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21433336/

相关文章:

德尔福XE2 : Possible to instantiate a FireMonkey Form in VCL application?

delphi - Google 通讯录 token 过期

delphi - 通过新 RTTI 处理索引属性时遇到问题 [D2010]

c# - 循环中匿名方法的不同 "execution context"的问题

c# - C# 事件处理程序委托(delegate)中的闭包?

delphi - 如何隐藏 TRibbon 页面?

delphi - 如何有效地检查一个字符串是否包含几个子字符串之一?

c# - 方法和匿名类型

C# 不能在匿名方法体内使用 ref 或 out 参数

c# - 如何确定c#中的匿名函数参数?