如何获取RxJS Subject或Observable的当前值?

Bac*_*tnz 160 javascript rxjs angular

我有一个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);
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Gün*_*uer 276

A SubjectObservable没有当前值.当一个值被发出时,它被传递给订阅者并且Observable完成它.

如果您想拥有一个当前值,请使用BehaviorSubject专为此目的而设计的值.BehaviorSubject保留最后发布的值并立即将其发送给新订阅者.

它还有一种getValue()获取当前值的方法.

  • 来自RxJS 5作者的重要提示:使用`getValue()`是一个巨大的红旗,你做错了.它就像一个逃生舱.通常,您使用RxJS执行的所有操作都应该是声明性的.`getValue()`势在必行.如果你正在使用`getValue()`,你有99.9%的可能做错了什么或很奇怪. (67认同)
  • 谢谢!!我不知道getValue()它让我的生活变得如此简单 (3认同)
  • @GünterZöchbauer 我的意思是:当发出一个新的布尔值时,我需要知道当前值来切换它。在这种情况下,使用“getValue()”是否合理? (3认同)
  • @IngoBürk 我可以证明您的建议合理的唯一方法是,如果您不知道 `foo$` 是一个 `BehaviorSubject`(即它被定义为 `Observable`,并且它可能是来自延迟源的热或冷)。然而,因为你接着在 `$foo` 本身上使用 `.next`,这意味着你的实现依赖于它*作为*一个 `BehaviorSubject`,所以没有理由不只是使用 `.value` 来获取当前值第一名。 (3认同)
  • @BenLesh 如果我有一个 `BehaviorSubject&lt;boolean&gt;(false)` 并且想切换它怎么办? (2认同)
  • @BenLesh getValue()对于执行瞬时操作非常有用,例如onClick-> dispatchToServer(x.getValue())但不要在可观察链中使用它. (2认同)

Ben*_*esh 124

应该 从"Observable/Subject"中获取值的唯一方法就是订阅!

如果你正在使用getValue()你在声明范式中做一些必要的事情.它在那里作为逃生舱,但99.9%的时间你不应该使用getValue().有一些有趣的事情getValue()可以做:如果主题已被取消订阅会抛出错误,如果主题因为错误而导致死亡等等,它将阻止您获取值.但是,再次,它会作为一个逃脱在罕见的情况下孵化.

有几种方法可以以"Rx-y"方式从Subject或Observable获取最新值:

  1. 使用BehaviorSubject:但实际订阅它.当您第一次订阅BehaviorSubject它时,将同步发送它收到的或之前初始化的值.
  2. 使用ReplaySubject(N):这将缓存N值并将它们重播给新订阅者.
  3. A.withLatestFrom(B):使用此运算符可B在observable A发出时从observable获取最新值.将为您提供数组中的两个值[a, b].
  4. A.combineLatest(B):使用此操作来得到最新的值AB每一次无论是AB发出.将为您提供数组中的两个值.
  5. shareReplay():通过a进行可观察多播ReplaySubject,但允许您在出错时重试observable.(基本上它为您提供了承诺-y缓存行为).
  6. publishReplay(),publishBehavior(initialValue),multicast(subject: BehaviorSubject | ReplaySubject),等:其它运营商,充分利用BehaviorSubjectReplaySubject.同一事物的不同风格,它们基本上通过汇集通过主题的所有通知来多播源可观察.您需要致电connect()订阅主题来源.

  • 你能详细说明为什么使用getValue()是一个红旗吗?如果我在用户单击按钮的那一刻只需要一次observable的当前值,该怎么办?我应该订阅价值并立即取消订阅吗? (15认同)
  • 有时候没关系。但是通常这表明该代码的作者正在做一些本不该做的非常必要的事情(通常带有副作用)。您也可以执行“ click $ .mergeMap(()=&gt; behaviorSubject.take(1))”来解决您的问题。 (3认同)
  • 我有一个“AuthenticationService”,它使用“BehaviourSubject”来存储当前登录状态(“boolean”“true”或“false”)。它为想要知道状态何时发生变化的订阅者公开了一个“isLoggedIn$”可观察对象。它还公开了一个“get isLoggedIn()”属性,该属性通过在底层“BehaviourSubject”上调用“getValue()”来返回当前登录状态——我的身份验证防护使用它来检查当前状态。对我来说,这似乎是“getValue()”的合理使用......? (3认同)
  • 如果您只想分派当前值(例如在单击时将其发送到服务器),则这样做非常有用,执行getValue()非常方便。但是在链接可观察的运算符时不要使用它。 (2认同)

Kfi*_*rez 9

我也遇到过类似的情况,即后期订阅者在其价值到达后订阅了该主题。

我发现ReplaySubject与BehaviorSubject相似,在这种情况下,它就像一个饰物。这是更好解释的链接:http : //reactivex.io/rxjs/manual/overview.html#replaysubject

  • 确保您使用的是 ReplaySubject(1),否则新订阅者将按顺序获取之前发出的每个值 - 这在运行时并不总是显而易见 (2认同)
  • 不完全相同,最大的区别是 ReplaySubject 在订阅时不会立即发出默认值,如果它的 `next()` 函数尚未被调用,而 BehaviourSubject 会。例如,当 BehaviourSubject 用作​​服务中可观察的数据源时,立即发出对于将默认值应用于视图非常方便 (2认同)

小智 6

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
// .................
// .................
// .................
Run Code Online (Sandbox Code Playgroud)

您可以从此处查看有关如何实现它的完整文章。 https://www.imkrish.com/blog/development/simple-way-get-value-from-observable