diff --git a/Falcon.SugarApi.Test/ShakingTests.cs b/Falcon.SugarApi.Test/ShakingTests.cs new file mode 100644 index 0000000..0c02375 --- /dev/null +++ b/Falcon.SugarApi.Test/ShakingTests.cs @@ -0,0 +1,42 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Falcon.SugarApi.Test +{ + /// + /// 任务防抖测试 + /// + [TestClass()] + public class ShakingTests + { + /// + /// 任务防抖测试 + /// + [TestMethod()] + public void RunTest() { + var showMsg = () => Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")} show message!"); + + var reMsg = () => $"{DateTime.Now.ToString("HH:mm:ss")} show message!"; + + var task = new Task(reMsg); + int span = 5; + var shaking = new Shaking(span); + + //showMsg(); + //await Task.Delay(5 * 1000); + //shaking.Run(showMsg); + Console.WriteLine($"以下方法调用3次,应该有两个输出,相隔{span}秒"); + Console.WriteLine(reMsg()); + shaking.Run(task); + task = new Task(reMsg); + shaking.Run(task); + Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")} {span}秒后记录第二个输出"); + Console.WriteLine(task.Result); + Console.WriteLine("任务完成!"); + } + } +} diff --git a/Falcon.SugarApi/Shaking.cs b/Falcon.SugarApi/Shaking.cs new file mode 100644 index 0000000..f3e17c0 --- /dev/null +++ b/Falcon.SugarApi/Shaking.cs @@ -0,0 +1,109 @@ +using System; +using System.Threading.Tasks; + +namespace Falcon.SugarApi +{ + /// + /// 防止抖动执行任务 + /// 每个任务加入后都会等待一段时间后开始执行。如果在等待期间有新的任务加入,旧任务会被放弃并重新记录等待时间。 + /// 用这种方式可以防止同样的类似任务被频繁触发, + /// 比如用户连续快速点击按钮导致点击事件处理程序多次执行,用此类可以保证只执行一次。 + /// 但是也产生了一些副作用,第一是不管怎么样方法总是会等待一定时间后延迟触发。 + /// 还有一个副作用,因为后加入的任务会导致先加入的未执行的任务被放弃,所以如果所有任务都必须执行,那就不要使用此类了。 + /// + public class Shaking:IDisposable + { + /// + /// 下一个要执行的任务 + /// + protected Task? Next { get; set; } + /// + /// 执行计时器 + /// + protected System.Timers.Timer Timer { get; set; } + /// + /// 等待执行时间 + /// + public int TimespanSeconds { get; set; } + /// + /// 使用默认方式实例化 + /// + public Shaking() : this(5) { } + /// + /// 实例化,默认抖动执行间隔5秒 + /// + /// 抖动执行时间间隔。秒 + public Shaking(int timeSpanSeconds) { + this.TimespanSeconds = timeSpanSeconds * 1000; + this.Timer = new System.Timers.Timer { + Interval = this.TimespanSeconds + }; + this.Timer.Elapsed += TimerTick; + this.Timer.Stop(); + } + /// + /// 时间到达,执行任务 + /// + /// + /// + protected void TimerTick(object? sender,EventArgs e) { + this.Timer.Stop(); + this.Timer.Dispose(); + if(this.Next == null) { + return; + } + var n = this.Next; + this.Next = null; + n.Start(); + } + /// + /// 新增任务 + /// 未执行任务将会放弃 + /// + /// 要执行的任务 + public void Run(Task task) { + this.Next = task; + if(this.Timer != null) { + this.Timer.Stop(); + this.Timer.Dispose(); + } + this.Timer = new System.Timers.Timer { + Interval = this.TimespanSeconds, + }; + this.Timer.Elapsed += TimerTick; + this.Timer.Start(); + } + /// + /// 新增任务委托 + /// 未执行任务将会放弃 + /// + /// 要执行的委托 + public void Run(Action action) => Run(new Task(action)); + /// + /// 释放资源,未执行的任务放弃 + /// + public void Dispose() { + if(this.Timer != null) { + this.Timer.Stop(); + this.Timer.Dispose(); + } + this.Next = null; + GC.SuppressFinalize(this); + } + /// + /// 立即执行任务 + /// + public void RunNow() { + var n = this.Next; + this.Next = null; + if(n == null) { + return; + } + if(this.Timer != null) { + this.Timer.Stop(); + this.Timer.Dispose(); + } + n.Start(); + } + } +}