在我写一个之前,我认为值得一提:RX有一个节流扩展方法,如果它们发生得太快就会丢弃事件。
因此,如果您要求它将事件限制为每5秒1次,如果您在0.1秒之后收到事件,然后在1秒之后收到第二个事件,您将获得一个事件,然后是静音。
我想要的是它在0.1秒之后举起第一个事件,但是在4.9秒后再举起另一个事件。
此外,如果我在0.1秒,1秒和2秒钟接收到事件,我希望它在0.1秒,5秒内提升事件,然后什么都没有,所以我不希望它捕获n个事件并且只发布一个事件n期的每期。
缓冲区反其道而行之,它会将所有内容保存5秒,然后引发事件,因此既不是节流也不是缓冲,而是介于两者之间。
有没有办法在现有框架中执行此操作,还是需要编写一个?
答案 0 :(得分:4)
我认为您必须编写自己的运算符,或者使用Window
进行一些操作。与其他评论一样,我对您的要求并不是100%肯定,但我试图在这些测试中捕获它们。
using System;
using System.Reactive.Linq;
using Microsoft.Reactive.Testing;
using NUnit.Framework;
[TestFixture]
public class Throttle : ReactiveTest
{
private TestScheduler _testScheduler;
private ITestableObservable<int> _sourceSequence;
private ITestableObserver<int> _observer;
[SetUp]
public void SetUp()
{
var windowPeriod = TimeSpan.FromSeconds(5);
_testScheduler = new TestScheduler();
_sourceSequence = _testScheduler.CreateColdObservable(
//Question does the window start when the event starts, or at time 0?
OnNext(0.1.Seconds(), 1),
OnNext(1.0.Seconds(), 2),
OnNext(2.0.Seconds(), 3),
OnNext(7.0.Seconds(), 4),
OnCompleted<int>(100.0.Seconds())
);
_observer = _testScheduler.CreateObserver<int>();
_sourceSequence
.Window(windowPeriod, _testScheduler)
.SelectMany(window =>
window.Publish(
shared => shared.Take(1).Concat(shared.Skip(1).TakeLast(1))
)
)
.Subscribe(_observer);
_testScheduler.Start();
}
[Test]
public void Should_eagerly_publish_new_events()
{
Assert.AreEqual(OnNext(0.1.Seconds(), 1), _observer.Messages[0]);
}
[Test]
public void Should_publish_last_event_of_a_window()
{
//OnNext(1.0.Seconds(), 2) is ignored. As OnNext(5.0.Seconds(), 3) occurs after it, and before the end of a window, it is yeiled.
Assert.AreEqual(OnNext(5.0.Seconds(), 3), _observer.Messages[1]);
}
[Test]
public void Should_only_publish_event_once_if_it_is_the_only_event_for_the_window()
{
Assert.AreEqual(OnNext(7.0.Seconds(), 4), _observer.Messages[2]);
Assert.AreEqual(OnCompleted<int>(100.0.Seconds()), _observer.Messages[3]);
}
[Test]
public void AsOneTest()
{
var expected = new[]
{
OnNext(0.1.Seconds(), 1),
//OnNext(1.0.Seconds(), 2) is ignored. As OnNext(5.0.Seconds(), 3) occurs after it, and before the end of a window, it is yeiled.
OnNext(5.0.Seconds(), 3),
OnNext(7.0.Seconds(), 4),
OnCompleted<int>(100.0.Seconds())
};
CollectionAssert.AreEqual(expected, _observer.Messages);
}
}