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


当前回答

可以创建订阅,然后在获取第一个发出的项之后销毁订阅。在下面的例子中,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

虽然这听起来有点夸张,但这只是另一个“可能”的解决方案,可以保持Observable类型并减少样板文件……

你总是可以创建一个扩展getter来获取Observable的当前值。

要做到这一点,你需要在global.d.t types声明文件中扩展Observable<T>接口。然后在observable.extension.ts文件中实现扩展getter,最后将类型和扩展文件都包含到应用程序中。

你可以参考这个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...
  });

我遇到过类似的情况,在Subject的价值到达后,迟来的订阅者才订阅它。

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

我在子组件中遇到了同样的问题,最初它必须拥有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

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

Subject或Observable没有当前值。当一个值被触发时,它被传递给订阅者,Observable就完成了对它的处理。

如果你想要一个当前值,请使用专门为此目的设计的BehaviorSubject。BehaviorSubject保留最后发出的值,并立即将其发出给新的订阅者。

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