// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. namespace Microsoft.Teams.Common.Extensions; public static class ActionExtensions { public static Action Debounce(this Action func, int milliseconds = 300) { CancellationTokenSource? cancelTokenSource = null; return arg => { cancelTokenSource?.Cancel(); cancelTokenSource?.Dispose(); cancelTokenSource = new CancellationTokenSource(); _ = Task.Delay(milliseconds, cancelTokenSource.Token) .ContinueWith(t => { if (t.IsCompletedSuccessfully) { try { func(arg); } catch { // Observe exception to prevent UnobservedTaskException. // Callers use fire-and-forget; there is no upstream to propagate to. } } }, TaskScheduler.Default); }; } public static Action Debounce(this Func func, int milliseconds = 300) { CancellationTokenSource? cancelTokenSource = null; return () => { cancelTokenSource?.Cancel(); cancelTokenSource?.Dispose(); cancelTokenSource = new CancellationTokenSource(); _ = DebounceCore(func, milliseconds, cancelTokenSource.Token); }; static async Task DebounceCore(Func func, int milliseconds, CancellationToken token) { try { await Task.Delay(milliseconds, token).ConfigureAwait(false); await func().ConfigureAwait(false); } catch (OperationCanceledException) { // Debounce was cancelled by a newer invocation } catch (Exception) { // Observe exception to prevent UnobservedTaskException. // Callers use fire-and-forget; there is no upstream to propagate to. } } } }