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();
+ }
+ }
+}