[UniRx] AsyncSubject 소개

13076 단어 UniRxUnity

AsyncSubject 소개

AsyncSubject는 Subject 시리즈 중 하나로 비동기 처리를 전문적으로 처리하는 Subject로 자리잡았다.
행동거지는 자바스크립트Promise와 사라Future와 크게 다르지 않다.장래에 하나의 결과만 확정할 때 사용할 수 있는 비동기 처리용Subject.
UniRxObservable에서 흐름의 길이는 1~무한 길이에 달한다.
이때 억지로 흐름의 길이를 1에 고정시키기 때문에 AsyncSubject는 Future/Promise와 완전히 같다는 생각에 기초하여 제작되었다.ObservableFuture/Promise보다 더 높은 개념이라고 할 수 있습니다)

AsyncSubject의 행동



(사진 참조: ReactiveXAsyncSubject의 행위는 다음과 같다.
  • ONNext에서도 바로 발매되지 않음
  • On Commpleted 실행 시 처음으로 On Next 1개만 발행
  • 발행된 OnNext가 마지막 값
  • Compulete된 AsyncSubject에 Subscribe를 적용한 경우 즉시 결과를 발표하는 On Next 및 On Commpleted
  • Promiseresolve(value)OnNext(value) + OnCompleted로 분해되어 이렇게 생각하면 이해하기 쉽다.

    용도


    일반적으로 Subscribe 이전에 발행된 On Next는 구독할 수 없습니다.
    그러나 이Subject의 경우 서브스크리브의 타이밍에 상관없이 AsyncSubject가 완성되면 반드시 On Next와 On Compuleted를 받을 수 있다.
    이러한 특성 때문에 비동기 처리를 위한 콜백이 매우 적합합니다(즉, Subject는 여기에 사용됩니다).

    예: 객체의 초기화 순서 제어


    갑자기 불규칙한 예지만 편하니까 소개할게요.
    객체 A와 객체 B 두 가지가 있습니다. 반드시 "A→B"순서로 초기화하십시오.
    유닛의 경우AsyncSubject는 스크립트의 실행 순서를 조정해서 실현할 수 있지만'실행 순서에 달려 있다'는 정보는 원본 코드에서 유닛으로 유출되기 때문에 불편하면 사용하고 싶지 않다.
    따라서 Script Execution Order를 사용하여 초기화 순서를 잘 실현해 보세요.

    설치 예


    Objecta (먼저 초기화하려는 쪽)
    using UniRx;
    using UnityEngine;
    
    namespace AsyncSubjectSample
    {
        /// <summary>
        /// 先に初期化されて欲しい方
        /// </summary>
        public class ObjectA : MonoBehaviour
        {
            private AsyncSubject<Unit> _initializedAsyncSubject = new AsyncSubject<Unit>();
    
            public IObservable<Unit> OnInitializedAsync
            {
                get { return _initializedAsyncSubject; }
            } 
    
            void Start()
            {
                Debug.Log("ObjectAのStartが実行されました");
    
                //ここでAの初期化処理
    
                Debug.Log("ObjectAの初期化が終わりました");
    
                //初期化完了通知
                _initializedAsyncSubject.OnNext(Unit.Default);
                _initializedAsyncSubject.OnCompleted();
            }
    
        }
    }
    
    ObjectB(A 후 초기화자)
    using UniRx;
    using UnityEngine;
    
    namespace AsyncSubjectSample
    {
        /// <summary>
        /// Aの後に初期化されて欲しい方
        /// </summary>
        public class ObjectB : MonoBehaviour
        {
    
            [SerializeField]
            private ObjectA objectA;
    
            void Start()
            {
                Debug.Log("ObjectBのStartが実行されました");
    
                // Aの初期化完了通知が来たらBを初期化する
                // OnInitializedAsyncが既にCompleted済みなら直ちに実行される
                objectA.OnInitializedAsync.Subscribe(_ => Initialize());
    
            }
    
            void Initialize()
            {
                //ここでBの初期化処理
    
                Debug.Log("ObjectBの初期化が終わりました");
            }
        }
    }
    

    결실

  • B의 Start()가 먼저 실행한 경우
  • ObjectBのStartが実行されました
    ObjectAのStartが実行されました
    ObjectAの初期化が終わりました
    ObjectBの初期化が終わりました
    
  • A의 Start()가 먼저 실행된 경우
  • ObjectAのStartが実行されました
    ObjectAの初期化が終わりました
    ObjectBのStartが実行されました
    ObjectBの初期化が終わりました
    
    이렇게 하면 AsyncSubject의 집행 순서와 상관없이 Start()의 순서에 따라 초기화해야 한다.

    총결산

    A → B는 기타AsyncSubject에 비해 행동이 다르므로 주의해야 한다.
    특히 Rx가 Observable의 흐름 길이를 1에 고정하는 것은 Promisse/Future와 완전히 같은 비동기 처리의 아이디어라고 할 수 있는데, 그 실현 중 하나가 바로 AsyncSubject다.

    Subject 랩 만들기 대상이 편하니까 소개해드려요.
    Single
    using System;
    using UniRx;
    
    namespace UniRxExt
    {
        /// <summary>
        /// 名前がRxJavaのSingleとかぶってるけど動作は違います
        /// </summary>
        public class Single : IObservable<Unit>, IDisposable
        {
            private readonly AsyncSubject<Unit> _asyncSubject = new AsyncSubject<Unit>();
            private readonly object lockObject = new object();
    
            public void Done()
            {
                lock (lockObject)
                {
                    if (_asyncSubject.IsCompleted) return;
                    _asyncSubject.OnNext(Unit.Default);
                    _asyncSubject.OnCompleted();
                }
            }
    
            public IDisposable Subscribe(IObserver<Unit> observer)
            {
                lock (lockObject)
                {
                    return _asyncSubject.Subscribe(observer);
                }
            }
    
            public void Dispose()
            {
                lock (lockObject)
                {
                    _asyncSubject.Dispose();
                }
            }
        }
    }
    
    사용법
    ObjectA
    using UniRx;
    using UniRxExt;
    using UnityEngine;
    
    namespace AsyncSubjectSample
    {
        /// <summary>
        /// 先に初期化されて欲しい方
        /// </summary>
        public class ObjectA : MonoBehaviour
        {
            private Single _single = new Single();
    
            public IObservable<Unit> OnInitializedAsync
            {
                get { return _single; }
            } 
    
            void Start()
            {
                Debug.Log("ObjectAのStartが実行されました");
    
                //ここでAの初期化処理
    
                Debug.Log("ObjectAの初期化が終わりました");
    
                //初期化完了通知
                // OnNext + OnCompletedをくっつけて呼べるだけ
                _single.Done();
            }
        }
    }
    

    좋은 웹페이지 즐겨찾기