我有一个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的当前值。我该怎么做呢?


当前回答

最好的方法是使用行为主语,下面是一个例子:

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

其他回答

可以创建订阅,然后在获取第一个发出的项之后销毁订阅。在下面的例子中,pipe()是一个函数,它使用一个可观察对象作为输入,并返回另一个可观察对象作为输出,同时不修改第一个可观察对象。

用Angular 8.1.0包"rxjs": "6.5.3", "rxjs-observable": "0.0.7"创建的示例

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

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

有两种方法可以实现这一点。

BehaviorSubject有一个getValue()方法,您可以在特定的时间点获取值。 你可以直接订阅BehaviorSubject,也可以将订阅的值传递给类成员、字段或属性。

我不会同时推荐这两种方法。

在第一种方法中,它是一种方便的方法,您可以随时获取值,您可以将其称为该时间点的当前快照。问题是你可以在你的代码中引入竞争条件,你可以在许多不同的地方和不同的时间调用这个方法,这很难调试。

第二种方法是大多数开发人员在他们想要订阅时使用的原始值,您可以跟踪订阅,以及何时取消订阅以避免进一步的内存泄漏,如果您真的非常想将其绑定到一个变量,并且没有其他方法来连接它,则可以使用这种方法。

我建议,再看看你的用例,你在哪里使用它?例如,当你调用任何API时,你想要确定用户是否登录,你可以结合其他观察数据:

const data$ = apiRequestCall$().pipe(
 // Latest snapshot from BehaviorSubject.
 withLatestFrom(isLoggedIn),
 // Allow call only if logged in.
 filter(([request, loggedIn]) => loggedIn)
 // Do something else..
);

在angular的情况下,你可以通过管道数据$ | async直接使用它到UI。

另一种方法,如果你想/可以使用async await(必须在async函数中),你可以在现代Rxjs中做到这一点:

 async myFunction () {
     const currentValue = await firstValueFrom(
      of(0).pipe(
        withLatestFrom(this.yourObservable$),
        map((tuple) => tuple[1]),
        take(1)
      )
    );
    // do stuff with current value

 }

 

这将发出一个值“Right away”,因为withLatestFrom,然后将解析承诺。

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

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

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