我想编写一个类似于 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/