[javascript] RxJS Subject 또는 Observable의 현재 가치를 얻는 방법?

Angular 2 서비스가 있습니다.

import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject}    from 'rxjs/Subject';

@Injectable()
export class SessionStorage extends Storage {
  private _isLoggedInSource = new Subject<boolean>();
  isLoggedIn = this._isLoggedInSource.asObservable();
  constructor() {
    super('session');
  }
  setIsLoggedIn(value: boolean) {
    this.setItem('_isLoggedIn', value, () => {
      this._isLoggedInSource.next(value);
    });
  }
}

모든 것이 잘 작동합니다. 그러나 구독 할 필요가없는 다른 구성 요소가 있으며 특정 시점에서 isLoggedIn의 현재 값을 가져와야합니다. 어떻게해야합니까?



답변

A Subject또는 Observable현재 값이 없습니다. 값이 방출되면 구독자에게 전달되고 값 Observable이 완료됩니다.

현재 값을 원한다면 BehaviorSubject정확히 그 목적을 위해 설계된 값을 사용하십시오 . BehaviorSubject마지막으로 방출 된 값을 유지하고 새로운 가입자에게 즉시 방출합니다.

getValue()현재 값을 얻는 방법도 있습니다 .


답변

당신이 유일한 방법 해야한다 “에서”값을 얻지는 관찰 가능한 / 주제 구독 함께!

당신이 사용 getValue()하고 있다면 선언적 패러다임에서 명령적인 일을하고있는 것입니다. 탈출구로 있지만 99.9 %는 사용하지 않아야합니다 getValue(). 몇 가지 흥미로운 일 getValue()이 있습니다. 주체가 구독을 취소하면 오류가 발생하고 오류로 인해 주제가 죽은 경우 값을 얻지 못하게됩니다. 그러나 다시, 탈출로 드문 상황에 부화.

“Rx-y”방식으로 Subject 또는 Observable에서 최신 값을 얻는 방법에는 여러 가지가 있습니다.

  1. 사용 BehaviorSubject: 그러나 실제로 구독 . 처음 구독 BehaviorSubject하면 수신하거나 초기화 한 이전 값을 동 기적으로 전송합니다.
  2. Using a ReplaySubject(N): N값 을 캐시 하고 새 구독자에게 재생합니다.
  3. A.withLatestFrom(B):이 연산자를 사용하여 관찰 B가능 A방출 시 관찰 가능 값에서 최신 값을 가져옵니다 . 배열의 두 값을 모두 제공합니다 [a, b].
  4. A.combineLatest(B): 사용이 연산자는 가장 최근의 값을 얻을 A하고 B때마다 하나 A또는 B방출한다. 배열의 두 값을 모두 제공합니다.
  5. shareReplay():를 통해 Observable 멀티 캐스트를 작성 ReplaySubject하지만 오류가 발생하면 Observable을 재 시도 할 수 있습니다. 기본적으로 캐쉬 동작을 약속합니다.
  6. publishReplay(), publishBehavior(initialValue), multicast(subject: BehaviorSubject | ReplaySubject), 등 : 다른 사업자를 활용 BehaviorSubject하고 ReplaySubject. 같은 것의 다른 풍미, 그들은 기본적으로 주제를 통해 모든 알림을 깔아서 관찰 가능한 소스를 멀티 캐스트합니다. connect()제목으로 소스를 구독 하려면 전화해야합니다 .

답변

나는 늦은 구독자가 그 가치에 도달 한 후 주제를 구독하는 비슷한 상황이 있었다.

이 경우 BehaviorSubject와 비슷한 ReplaySubject 가 매력처럼 작동 한다는 것을 알았 습니다 . 더 나은 설명으로 연결되는 링크는 다음과 같습니다. http://reactivex.io/rxjs/manual/overview.html#replaysubject


답변

const observable = of('response')

function hasValue(value: any) {
  return value !== null && value !== undefined;
}

function getValue<T>(observable: Observable<T>): Promise<T> {
  return observable
    .pipe(
      filter(hasValue),
      first()
    )
    .toPromise();
}

const result = await getValue(observable)
// Do the logic with the result
// .................
// .................
// .................

여기에서 구현 방법에 대한 전체 기사를 확인할 수 있습니다.
https://www.imkrish.com/how-to-get-current-value-of-observable-in-a-clean-way/


답변

하위 구성 요소에서 처음에 주제의 현재 값을 가져야하는 동일한 문제가 발생 한 다음 주제를 구독하여 변경 사항을 듣습니다. 구성 요소가 다음과 같이 액세스 할 수 있도록 서비스의 현재 값을 유지합니다.

import {Storage} from './storage';
import {Injectable} from 'angular2/core';
import {Subject}    from 'rxjs/Subject';

@Injectable()
export class SessionStorage extends Storage {

  isLoggedIn: boolean;

  private _isLoggedInSource = new Subject<boolean>();
  isLoggedIn = this._isLoggedInSource.asObservable();
  constructor() {
    super('session');
    this.currIsLoggedIn = false;
  }
  setIsLoggedIn(value: boolean) {
    this.setItem('_isLoggedIn', value, () => {
      this._isLoggedInSource.next(value);
    });
    this.isLoggedIn = value;
  }
}

현재 값이 필요한 구성 요소는 서비스에서 액세스 할 수 있습니다.

sessionStorage.isLoggedIn

이것이 올바른 습관인지 확실하지 않습니다 🙂


답변

비슷한 찾고 대답을 downvoted했다. 그러나 제한된 경우에 대해 내가 제안하는 것을 정당화 할 수 있다고 생각합니다.


관찰 가능 항목에 현재 값 이없는 것이 사실이지만 , 종종 즉시 사용 가능한 값을 갖습니다. 예를 들어 redux / flux / akita 상점의 경우 여러 관측 가능 항목을 기반으로 중앙 상점에 데이터를 요청할 수 있으며 일반적으로 해당 값을 즉시 사용할 수 있습니다.

이 경우이면 subscribe값이 즉시 돌아옵니다.

그럼 당신이 서비스에 전화를했다 말, 및 완료에 당신이 상점에서 무언가의 최신 값을 싶어 할 가능성이 방출되지 않을 수도 있음 :

당신은 이것을 시도 할 수 있습니다 (그리고 가능한 한 많은 것을 파이프 안에 보관해야합니다) :

 serviceCallResponse$.pipe(withLatestFrom(store$.select(x => x.customer)))
                     .subscribe(([ serviceCallResponse, customer] => {

                        // we have serviceCallResponse and customer 
                     });

이것의 문제는 2 차 관측 가능 값이 방출 될 때까지 차단 될 수 있다는 것입니다.

나는 최근 에 값을 즉시 사용할 수있는 경우에만 관측 가능 항목을 평가해야한다는 것을 알았 으며, 더 중요하게는 그렇지 않은 경우를 감지 할 수 있어야했습니다. 나는 이것을 끝내었다.

 serviceCallResponse$.pipe()
                     .subscribe(serviceCallResponse => {

                        // immediately try to subscribe to get the 'available' value
                        // note: immediately unsubscribe afterward to 'cancel' if needed
                        let customer = undefined;

                        // whatever the secondary observable is
                        const secondary$ = store$.select(x => x.customer);

                        // subscribe to it, and assign to closure scope
                        sub = secondary$.pipe(take(1)).subscribe(_customer => customer = _customer);
                        sub.unsubscribe();

                        // if there's a delay or customer isn't available the value won't have been set before we get here
                        if (customer === undefined)
                        {
                           // handle, or ignore as needed
                           return throwError('Customer was not immediately available');
                        }
                     });

위의 모든 subscribe것에서 나는 @Ben이 논의한 것처럼 값을 얻는 데 사용 하고 있습니다. .value내가있는 경우에도 속성을 사용하지 않습니다 BehaviorSubject.


답변

과잉으로 들릴 수도 있지만 이것은 Observable 유형 을 유지 하고 상용구를 줄이는 또 다른 “가능한”솔루션입니다 …

Observable의 현재 값을 얻기 위해 항상 확장 getter 를 작성할 수 있습니다 .

이렇게하려면 타이핑 선언 파일 Observable<T>에서 인터페이스 를 확장해야 global.d.ts합니다. 그런 다음 파일에 확장 getter 를 구현 observable.extension.ts하고 마지막으로 입력과 확장 파일을 모두 애플리케이션에 포함하십시오.

StackOverflow 응답 을 참조 하여 확장을 Angular 응용 프로그램에 포함시키는 방법을 알 수 있습니다 .

// global.d.ts
declare module 'rxjs' {
  interface Observable<T> {
    /**
     * _Extension Method_ - Returns current value of an Observable.
     * Value is retrieved using _first()_ operator to avoid the need to unsubscribe.
     */
    value: Observable<T>;
  }
}

// observable.extension.ts
Object.defineProperty(Observable.prototype, 'value', {
  get <T>(this: Observable<T>): Observable<T> {
    return this.pipe(
      filter(value => value !== null && value !== undefined),
      first());
  },
});

// using the extension getter example
this.myObservable$.value
  .subscribe(value => {
    // whatever code you need...
  });