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

IT技术 javascript angular rxjs
2021-01-14 20:49:15

我有一个 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 的当前值。我怎样才能做到这一点?

6个回答

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

如果您想获得当前值,请使用BehaviorSubject专为此目的而设计的BehaviorSubject保留最后发出的值并立即将其发送给新订阅者。

它还具有getValue()获取当前值的方法。

@IngoBürk 我可以证明您的建议合理的唯一方法是,如果您不知道那foo$是一个BehaviorSubject(即它被定义为Observable并且可能来自延迟来源的热或冷)。但是,因为你接下来要使用.next$foo本身,这意味着你的实现依赖于它一个BehaviorSubject如此有不只是使用没有任何理由.value让摆在首位的电流值。
2021-03-19 20:49:15
RxJS 5 作者的重要说明:使用getValue()是一个巨大的危险信号,你做错了什么。它在那里作为逃生舱口。通常,您使用 RxJS 所做的一切都应该是声明性的。getValue()势在必行。如果您正在使用getValue()那么您有 99.9% 的机会做错或奇怪的事情。
2021-03-20 20:49:15
@BenLesh 如果我有一个BehaviorSubject<boolean>(false)并且想切换它怎么办?
2021-03-22 20:49:15
嗨,这是我的错,它们现在在 rxjs 5 中是一样的。上面的源代码链接指的是 rxjs4。
2021-03-26 20:49:15
@BenLesh getValue() 非常有用,可以做一个瞬时动作,比如 onClick->dispatchToServer(x.getValue()) 但不要在可观察链中使用它。
2021-04-09 20:49:15

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

如果您正在使用,getValue()那么您就是在声明式范式中做一些必要的事情。它作为逃生舱口存在,但在99.9% 的情况下您不应该使用getValue(). 有一些有趣的事情getValue()会做:如果主题已取消订阅,它将抛出错误,如果主题因错误而死亡,它将阻止您获得值等。但是,再次,它是作为一种逃避在罕见的情况下孵化。

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

  1. 使用BehaviorSubject:但实际上订阅了它当您第一次订阅BehaviorSubject它时,它将同步发送它接收到或初始化的先前值。
  2. 使用 a ReplaySubject(N):这将缓存N值并将它们重播给新订阅者。
  3. A.withLatestFrom(B):B当 observableA发出时,使用此运算符从 observable 获取最新值会给你一个数组中的两个值[a, b]
  4. A.combineLatest(B): 使用此运算符从AB每次发出AB发出获取最新值会给你一个数组中的两个值。
  5. shareReplay(): 通过 a 进行 Observable 多播ReplaySubject,但允许您在出错时重试 observable。(基本上它为您提供了Promise的缓存行为)。
  6. publishReplay()publishBehavior(initialValue)multicast(subject: BehaviorSubject | ReplaySubject)等: 其他利用BehaviorSubject和 的运算符ReplaySubject同一事物的不同风格,它们基本上通过将所有通知汇集到一个主题来多播源 observable。您需要调用connect()以订阅带有主题的源。
你能详细说明为什么使用 getValue() 是一个危险信号吗?如果我只需要一次 observable 的当前值,在用户单击按钮的那一刻怎么办?我应该订阅该值并立即取消订阅吗?
2021-03-14 20:49:15
很好的解释!实际上,如果你能保持 Observable 并使用这些方法,这是一个更好的方法。在到处都使用 Observable 的typescript上下文中,但只有少数被定义为 BehaviourSubject,那么它的代码一致性就会降低。你提出的方法让我可以在任何地方保留 Observable 类型。
2021-03-19 20:49:15
如果您只想发送当前值(例如单击时将其发送到服务器),那很好,执行 getValue() 非常方便。但在链接可观察操作符时不要使用它。
2021-03-27 20:49:15
我有一个AuthenticationService使用 aBehaviourSubject来存储当前登录状态(boolean truefalse)。isLoggedIn$为想要知道状态何时发生变化的订阅者公开了一个可观察的对象。它还公开了一个get isLoggedIn()属性,该属性通过调用getValue()底层返回当前登录状态BehaviourSubject- 我的身份验证卫士使用它来检查当前状态。getValue()对我来说似乎是一个明智的用法......?
2021-04-05 20:49:15
有时候没事。但通常这表明代码的作者正在做一些他们不应该做的非常必要的事情(通常有副作用)。你也可以click$.mergeMap(() => behaviorSubject.take(1))解决你的问题。
2021-04-07 20:49:15

我遇到过类似的情况,迟到的订阅者在它的value到达后订阅它。

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

这对我的 Angular4 应用程序有帮助 - 我不得不将订阅从组件构造函数移到 ngOnInit()(此类组件跨路由共享),只是离开这里以防有人遇到类似问题
2021-03-21 20:49:15
不完全相同,最大的区别在于,如果 ReplaySubject 的next()函数尚未被调用,它在订阅时不会立即发出默认值,而 BehaviourSubject 会。例如,当 BehaviourSubject 用作​​服务中可观察的数据源时,立即发出对于将默认值应用于视图非常方便
2021-03-23 20:49:15
我在使用 Angular 5 应用程序时遇到问题,我使用服务从 api 获取值并在不同组件中设置变量。我正在使用主题/可观察对象,但在路线更改后它不会推送值。ReplaySubject 替代了 Subject 并解决了所有问题。
2021-04-04 20:49:15
确保您正在使用 ReplaySubject(1) 否则新订阅者将按顺序获得每个先前发出的值 - 这在运行时并不总是很明显
2021-04-08 20:49:15
@Drenai 据我了解 ReplaySubject(1) 的行为与 BehaviorSubject() 相同
2021-04-10 20:49:15
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/blog/development/simple-way-get-value-from-observable

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

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

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

如果您需要组件视图中 observable 的值,您可以只使用async管道。
2021-03-25 20:49:15