如何在Delphi中编写Debounce()过程? [英] How to write a Debounce() procedure in Delphi?

查看:85
本文介绍了如何在Delphi中编写Debounce()过程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个类似于Java中通常实现的反跳过程。例如,Underscore.js中的 debounce函数

I would like to write a Debounce procedure similar to ones commonly implemented in Javascript. For example the debounce function in Underscore.js.

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

I think it could look like this:

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

,可以这样使用:

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

可能的实施#1

Debounce()过程将检查自从调用目标方法以来已经有多长时间了。如果在X时间内调用了目标方法,则该方法将被延迟。

The Debounce() procedure would check how long it's been since the target method was called. The target method call would be delayed if it's been called in X time.

伪代码版本:

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。有任何想法吗?

The problem I'm facing is I need some way to identify the target procedure. My first thought was to use the method address of the target procedure as the ID. For example:
ID := Address(Foo); ID := Addr(Foo);
But this doesn't work with anonymous methods as they use the same address in my tests. Ideally the ID should be automatically generated. Any ideas?

推荐答案

您说的所有匿名过程的地址都相同,但这是不可能的。相反,我怀疑您尝试输入错误的值。您说您呼叫了地址,但没有此功能。您可能是指 Addr ,它与 @ 运算符相同。但是,这为您提供了 MyAnonymousProcedure 形式参数的地址,而不是其中存储的地址。每次调用该函数时,参数很有可能具有相同的地址。

You say the addresses of all your anonymous procedures are the same, but that's impossible. Instead, I suspect you're trying the wrong value. You say you call Address, but there's no such function. You probably mean Addr, which is the same as the @ operator. However, that gives you the address of the MyAnonymousProcedure formal parameter, not the address stored in it. It's quite possible that the parameter has the same address each time you call the function.

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

You're looking for a way of identifying distinct procedure references. The reference itself should suffice. You could use a TDictionary<TProc, TDateTime> to map procedures to their last call times.

危险是这样,每次运行时,您都会使用过程常量调用 Debounce 函数,您可能最终构造了该过程对象的全新实例,因此其地址将与任何其他实例都不相同。

The danger is that each time you run you call your Debounce function with a procedure literal, you may end up constructing an entirely new instance of that procedure object, so its address will be different from any previously constructed procedure, even if it uses the same code and the same captured variable values.

JavaScript版本容易遇到相同的问题,因此它不会使用以前构造的过程,即使它使用相同的代码和相同的捕获变量值。尝试完全识别功能。而是返回一个 new函数,该函数包装传入的内容。新函数添加了延迟行为。在Delphi中,它可以像这样工作:

The JavaScript version is susceptible to the same problem, which is why it doesn't try to identify the function at all. Instead, it returns a new function that wraps the one passed in. The new function adds the delay behavior. In Delp it could work something like this:

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版本中是正确的。那是简单的情况,因为它不需要任何机制来延迟执行。但是,它表明您实际上并不需要区分不同的过程引用的方法,而这就是您之前遇到的问题。

This version works as though the immediate parameter in the Underscore version is true. That's the easy case because it doesn't require any mechanism for delaying execution. However, it shows that you don't really need a way of distinguishing between different procedure references, and that's what you were stuck on before.

这篇关于如何在Delphi中编写Debounce()过程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆