Javascript 如何获取RxJS主体或可观察对象的当前值?

Javascript 如何获取RxJS主体或可观察对象的当前值?,javascript,angular,rxjs,Javascript,Angular,Rxjs,我有一个角度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>();

我有一个角度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);
    });
  }
}
从“/Storage”导入{Storage};
从'angular2/core'导入{Injectable};
从'rxjs/Subject'导入{Subject};
@可注射()
导出类会话存储扩展了存储{
private _isLoggedInSource=新主题();
isLoggedIn=这个。_isLoggedInSource.asObservable();
构造函数(){
超级(“会话”);
}
setIsLoggedIn(值:布尔值){
此.setItem(''isLoggedIn',值,()=>{
this._isLoggedInSource.next(值);
});
}
}

一切都很好。但我有另一个不需要订阅的组件,它只需要在某个时间点获取isLoggedIn的当前值。我如何才能做到这一点?

A
主题
可观察
没有当前值。当一个值被发出时,它被传递给订阅者,并且用它来完成
可观察的

如果要获得当前值,请使用专门为此目的设计的
BehaviorSubject
BehaviorSubject
保留最后发出的值,并立即将其发送给新订户


它还有一个方法
getValue()
来获取当前值。

我也遇到过类似的情况,即晚订户在主题值到达后订阅该主题

我发现,在这种情况下,与行为主体类似的行为主体就像一个符咒。 这里有一个更好的解释链接:

你应该“从”一个可观察/主题中获得价值的唯一方法是订阅! 如果您使用的是
getValue()
,那么您在声明性范例中执行的是命令式的操作。它是一个逃生舱,但是99.9%的时候你不应该使用
getValue()
有一些有趣的事情
getValue()
会做:如果主题被取消订阅,它会抛出一个错误,如果主题因为出错而死亡,它会阻止你获得一个值,等等,这是一个特殊情况下的逃生舱

有几种方法可以通过“Rx-y”方式从受试者或可观察对象处获取最新值:

  • 使用
    BehaviorSubject
    :但实际订阅它。当您首次订阅
    BehaviorSubject
    时,它将同步发送以前接收到或初始化的值
  • 使用
    ReplaySubject(N)
    :这将缓存
    N
    值并将其重播给新订阅者
  • A.withLatestFrom(B)
    :当可观测
    A
    发出时,使用此运算符从可观测
    B
    获取最新值。将在数组中为您提供两个值
    [a,b]
  • A.combinelatetest(B)
    :每次
    A
    B
    发出时,使用此运算符从
    A
    B
    获取最新值。将在数组中为您提供两个值
  • shareReplay()
    :通过
    ReplaySubject
    创建可观察的多播,但允许您在出现错误时重试可观察的多播。(基本上,它提供了promise-y缓存行为)
  • publishReplay()
    publishBehavior(initialValue)
    多播(主题:BehaviorSubject | ReplaySubject)
    ,等等:利用
    BehaviorSubject
    ReplaySubject
    的其他操作符。同一事物的不同风格,它们基本上通过将所有通知汇集到一个主题来多播可观察到的源。您需要调用
    connect()
    以订阅带有主题的源代码

  • 我在子组件中遇到了同样的问题,最初它必须具有主题的当前值,然后订阅主题以侦听更改。我只是维护服务中的当前值,以便组件可以访问,例如:

    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;
      }
    }
    

    不确定这是否是正确的做法:)

    您可以将上次发出的值与可观察值分开存储。然后在需要的时候阅读

    let lastValue: number;
    
    const subscription = new Service().start();
    subscription
        .subscribe((data) => {
            lastValue = data;
        }
    );
    
    一个相似的答案被否决了。但我认为我可以证明我在有限情况下的建议


    虽然一个可观察对象确实没有一个当前值,但通常它会有一个立即可用的值。例如,对于redux/flux/akita存储,您可以基于大量可观测数据从中央存储请求数据,该值通常会立即可用

    如果是这种情况,则当您订阅时,该值将立即返回

    假设您有一个对服务的调用,并且在完成时您希望从您的商店中获取某些可能不会发出的最新值:

    您可以尝试这样做(并且您应该尽可能将东西“放在管道内”):

    问题是它会一直阻塞,直到第二个可观察对象发出一个值,而这个值可能永远不会出现

    我发现自己最近需要评估一个可观察的,只有当一个值立即可用时才进行评估,更重要的是,我需要能够检测到它是否可用。我最终做了这样的事:

     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
    属性,即使我有
    行为主体

    const observable=of('response'))
    
    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
    // .................
    // .................
    // .................
    
    函数hasValue(值:任意){ 返回值!==null&&value!==未定义; } 函数getValue(可观察:可观察):承诺{ 可观测回波 .烟斗( 过滤器(hasValue), 第一() ) .toPromise(); } 常量结果=等待获取值(可观察) //对结果进行逻辑分析 // ................. // ................. // .................
    您可以在这里查看关于如何实现它的完整文章。
    虽然听起来有些过分,但这只是另一个“po”
     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');
                            }
                         });
    
    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
    // .................
    // .................
    // .................
    
    var sub = new rxjs.BehaviorSubject([0, 1])
    sub.next([2, 3])
    setTimeout(() => {sub.next([4, 5])}, 1500)
    sub.subscribe(a => console.log(a)) //2, 3 (current value) -> wait 2 sec -> 4, 5
    
      ngOnInit() {
    
        ...
    
        // If loading with previously saved value
        if (this.controlValue) {
    
          // Take says once you have 1, then close the subscription
          this.selectList.pipe(take(1)).subscribe(x => {
            let opt = x.find(y => y.value === this.controlValue);
            this.updateValue(opt);
          });
    
        }
      }