UniRxでThrottle.Subscribe中に値を変更すると、その値が無視されてしまうので気をつけて。という備忘録

確かによく考えるとそうなるかもしれないけれど、微妙に直感的ではなくて引っかかった挙動があったのでメモ。

簡単なコードから話を始めます。

var hoge = new ReactiveProperty<int>(0);

hoge
    .Subscribe(x =>
    {
        Debug.Log($"{Time.frameCount} Subscribe Start hoge = {x}");
        hoge.Value = 3;
        Debug.Log($"{Time.frameCount} Subscribe End hoge = {x}");
    })
    .AddTo(this);

await UniTask.DelayFrame(10);

Debug.Log($"{Time.frameCount} Update hoge = 1");
hoge.Value = 1;

一瞬こんがらがりますが、実行結果が以下のようになるのは自明でしょう。

1 Subscribe Start hoge = 0
1 Subscribe End hoge = 0
11 Update hoge = 1
11 Subscribe Start hoge = 1
11 Subscribe Start hoge = 3
11 Subscribe End hoge = 3
11 Subscribe End hoge = 1

もちろん、最終的にhoge.Valueは3ですし、最後にSubscribeで渡ってくる値も3です。

続いて、DelayFrameを噛ませてみました。

hoge
    .DelayFrame(1)
    .Subscribe(x =>

ちょっとややこしくなってきましたが、まあこうなるのは分かるでしょう。

3 Subscribe Start hoge = 0
3 Subscribe End hoge = 0
5 Subscribe Start hoge = 3
5 Subscribe End hoge = 3
11 Update hoge = 1
12 Subscribe Start hoge = 1
12 Subscribe End hoge = 1
14 Subscribe Start hoge = 3
14 Subscribe End hoge = 3

さっきと変わらず、最終的にhoge.Valueは3ですし、最後にSubscribeで渡ってくる値も3です。

ここからが本題、さっきのDelayFrameをThrottleFrameに変えてみました。

hoge
    .ThrottleFrame(1)
    .Subscribe(x =>

この実行結果は

3 Subscribe Start hoge = 0
3 Subscribe End hoge = 0
11 Update hoge = 1
12 Subscribe Start hoge = 1
12 Subscribe End hoge = 1

になります。
最終的なhoge.Valueは3になりますが、Subscribeに3が渡ってくることはありません。

気持ちとしては13フレーム目で3が渡ってきて欲しいんですが、確かにOnNext中に値が変わったらThrottleに巻き込まれて握り潰されちゃうのかなーと思った挙動でした。