var i = 0;
var saveSource = Observable.Interval(TimeSpan.FromMilliseconds(200)).Select(x => i++);

var throttledClicks = saveSource 
    .Throttle(TimeSpan.FromMilliseconds(2000)) // Throttle for 2000 milliseconds
    .Subscribe(x => Save()"));

How can I execute first event and ignore others until 2s has passed since the previous one and execute it only once. Execute it immediately if more than 2s has passed.

Real life example is calling Save method that should execute immediately if previous one was executed more than 2s ago and wait until 2s has passed to execute it (only once if multiple Save events have arrived). Save does not accepts any argument so x is not important.

1

There are 1 best solutions below

0
Oleg Dok On

Probably the task is for Sample extension method?

var throttledClicks = saveSource 
    .Sample(TimeSpan.FromSeconds(2)) // Sample every 2000 milliseconds if any
    .Subscribe(_ => Save());

Sample takes the last emission in every 2 seconds and propagates it.

Another option is to take 1st emission from every time interval as follows:

var throttledClicks = saveSource 
    .Window(TimeSpan.FromSeconds(2))
    .Select(window=>window.FirstAsync())
    .Concat()
    .Subscribe(_ => Save()"));

If it is still not exactly what you are looking for, then here is a more robust solution:

var throttledClicks = saveSource 
    .Select(i => new { TimestampUtc = DateTime.UtcNow, Value = i })
    .Scan((state, i) => i.TimestampUtc - state.TimestampUtc >= TimeSpan.FromSeconds(2) ? i : state)
    .DistinctUntilChanged()
    .Select(i => i.Value) // <-- optional
    .Subscribe(_ => Save());