ThrottleFirstLast
1. 概要
ThrottleFirstLast は、ソースシーケンスから最初に届いた値を即座に下流へ発行し、さらにスロットリング期間の終了時に最後に受け取った値も発行するオペレーターです。
ThrottleFirst の即時応答性と ThrottleLast の最新値保証を組み合わせたオペレーターです。最初の値に即座に反応しつつ、期間中に届いた最後の値も漏らさず下流に流したい場合に適しています。
2. シグネチャ
TimeSpan によるスロットリング
csharp
public static Observable<T> ThrottleFirstLast<T>(
this Observable<T> source,
TimeSpan timeSpan)csharp
public static Observable<T> ThrottleFirstLast<T>(
this Observable<T> source,
TimeSpan timeSpan,
TimeProvider timeProvider)最初の値を即座に発行し、timeSpan 経過後に期間中の最後の値を発行します。
csharp
source.ThrottleFirstLast(TimeSpan.FromMilliseconds(500))サンプラー Observable によるスロットリング
csharp
public static Observable<T> ThrottleFirstLast<T, TSample>(
this Observable<T> source,
Observable<TSample> sampler)最初の値を即座に発行し、sampler が次の値を発行した時点で期間中の最後の値を発行します。
csharp
source.ThrottleFirstLast(Observable.Interval(TimeSpan.FromSeconds(1)))非同期関数によるスロットリング
csharp
public static Observable<T> ThrottleFirstLast<T>(
this Observable<T> source,
Func<T, CancellationToken, ValueTask> sampler,
bool configureAwait = true)最初の値を即座に発行し、sampler 非同期関数が完了した時点で期間中の最後の値を発行します。
csharp
source.ThrottleFirstLast(async (value, ct) =>
{
await Task.Delay(TimeSpan.FromMilliseconds(500), ct);
})overload の使い分け
| overload | 使う場面 |
|---|---|
TimeSpan | 固定のスロットリング期間で十分な場合(最も一般的) |
TimeSpan, TimeProvider | ユニットテストで時間を制御したい場合 |
Observable<TSample> | 外部イベントでスロットリング期間を制御したい場合 |
Func<T, CancellationToken, ValueTask> | 値に応じてスロットリング期間を動的に変えたい場合 |
3. マーブルダイアグラム
最初の値が即座に発行され、スロットリング期間が開始します。期間の終了時に、期間中に最後に受け取った値が追加で発行されます。最初の値と最後の値が同じ場合(期間中に 1 つしか値が届かなかった場合)は、1 つだけ発行されます。
4. サンプルコード
csharp
using R3;
// スクロールイベント:即座に応答しつつ、最終位置も捕捉
scrollEventObservable
.ThrottleFirstLast(TimeSpan.FromMilliseconds(200))
.Subscribe(pos => UpdateScrollPosition(pos));
// ドラッグ操作:開始位置と最新位置の両方を取得
dragObservable
.ThrottleFirstLast(TimeSpan.FromMilliseconds(100))
.Subscribe(pos => HandleDragPosition(pos));
// FakeTimeProvider を使ったテスト
var fakeTime = new FakeTimeProvider();
var results = new List<int>();
var subject = new Subject<int>();
subject
.ThrottleFirstLast(TimeSpan.FromSeconds(1), fakeTime)
.Subscribe(x => results.Add(x));
subject.OnNext(1); // 即座に発行
subject.OnNext(2);
subject.OnNext(3);
// results: [1]
fakeTime.Advance(TimeSpan.FromSeconds(1));
// results: [1, 3] — 期間終了時に最後の値も発行5. 補足
ThrottleFirst / ThrottleLast との違い
| オペレーター | 発行する値 | 応答性 | 最新値の保証 |
|---|---|---|---|
| ThrottleFirst | 最初の値のみ | 即座 | なし |
| ThrottleLast | 最後の値のみ | 期間終了時 | あり |
| ThrottleFirstLast | 最初 + 最後の値 | 即座 | あり |
ThrottleFirstLast は応答性と最新値の保証を両立しますが、1 つの期間あたり最大 2 つの値を発行する点に注意してください。
フレームベースの版は ThrottleFirstLastFrame を参照してください。