🫠

UniRx部分のSubscribeAwaitへの移行

2024/02/06に公開

背景

古いコードをみてると、UniRxのロジックからUniTaskへの移行したいなということが多い.
でも各所でObservableが溢れているので、
どんなふうに移行するのがスムーズかなと考えてみた

サンプル

シンプルなボタンイベントを考える
下記のようなコードを実行してみる

public class Sample : MonoBehaviour
{
    [SerializeField] private Button button;

    private void Start()
    {
        // パターン1.
        button.OnClickAsObservable()
            .Subscribe(async _ => await Run())
            .AddTo(this);

        // パターン2. 
        button.OnClickAsObservable()
            .Subscribe(_ => Run().Forget())
            .AddTo(this);
        
        // パターン3. 
        button.OnClickAsAsyncEnumerable()
            .SubscribeAwait(async _ => await Run())
            .AddTo(this);
        
        // パターン4. 
        button.OnClickAsObservable()
            .ToUniTaskAsyncEnumerable()
            .SubscribeAwait(async _ => await Run())
            .AddTo(this);

    }

    private async UniTask Run()
    {
        Debug.Log("Before");
        await UniTask.Delay(TimeSpan.FromSeconds(5));
        Debug.Log("After");
    }
}

挙動

5秒間で2回ボタンを連打したときの挙動は下記のようになる

パターン1,2. 即時連続実行される

Before
Before
After
After

パターン3. 一度だけ実行される (実行中の連打は無視)

Before
After

パターン4. 即時実行されずにイベントは逐次実行される

Before
After
Before
After

パターン1は、void asyncのコードになるので、望ましくない.
パターン2は、即時実行されてしまい重複的に処理を行うので好ましくない
パターン3は、UniTaskだけで完結していて、重複処理も防止できており最も好ましい. ただイベントソースから書き直すような対応が必要なので、Observableが各所に散らばっている移行期には利用しづらい
パターン4は、重複処理が防げているが、処理中のイベントをQueuingしてしまっているので、惜しい

移行期には、パターン4にthrottle挟むなり、Rxの独自オペレーター挟むなりで連打防止しつつ、最終的にはパターン3に切り替えるのがいいのかなとおもった。

Discussion