113

我想知道有什么用asObservable

根据文档:

隐藏源序列身份的可观察序列。

但是为什么你需要隐藏序列呢?

4

3 回答 3

217

何时使用 Subject.prototype.asObservable()

这样做的目的是防止从 API 中泄露 Subject 的“观察者端”。基本上是为了防止当您不希望人们能够“下一个”进入结果的 observable 时出现泄漏的抽象。

例子

(注意:这真的不是你应该如何将这样的数据源变成一个 Observable,而是你应该使用new Observable构造函数,见下文)。

const myAPI = {
  getData: () => {
    const subject = new Subject();
    const source = new SomeWeirdDataSource();
    source.onMessage = (data) => subject.next({ type: 'message', data });
    source.onOtherMessage = (data) => subject.next({ type: 'othermessage', data });
    return subject.asObservable();
  }
};

myAPI.getData()现在,当有人从他们无法next重视结果中获得可观察的结果时:

const result = myAPI.getData();
result.next('LOL hax!'); // throws an error because `next` doesn't exist

new Observable()不过,您通常应该使用

在上面的示例中,我们可能正在创建一些我们不打算这样做的东西。一方面,getData()它不像大多数 observables 那样懒惰,它会立即创建底层数据源SomeWeirdDataSource(可能还有一些副作用)。这也意味着,如果您retryrepeat由此产生的 observable,它不会像您想象的那样工作。

最好将数据源的创建封装在 observable 中,如下所示:

const myAPI = {
  getData: () => return new Observable(subscriber => {
    const source = new SomeWeirdDataSource();
    source.onMessage = (data) => subscriber.next({ type: 'message', data });
    source.onOtherMessage = (data) => subscriber.next({ type: 'othermessage', data });
    return () => {
      // Even better, now we can tear down the data source for cancellation!
      source.destroy();
    };
  });
}

使用上面的代码,任何行为,包括使其“不懒惰”都可以使用 RxJS 现有的操作符在可观察对象之上组成。

于 2016-05-02T18:20:19.810 回答
14

ASubject可以同时充当 anobserver和 an observable

AnObervable有 2 种方法。

  • 订阅
  • 退订

每当您订阅anobservable时,您都会得到一个observerwhich 上有nexterrorcomplete方法。

您需要隐藏序列,因为您不希望流源在每个组件中都公开可用。你可以参考@BenLesh的例子,同样的。

PS:当我第一次接触 Reactive Javascript 时,我无法理解asObservable。因为我必须确保我清楚地了解基础知识,然后再选择asObservable. :)

于 2019-08-19T10:46:14.527 回答
5

除了这个答案,我还要提到,在我看来,这取决于所使用的语言。

对于像JavaScript这样的无类型(或弱类型)语言,通过像asObservable()方法一样创建委托对象来向调用者隐藏源对象可能是有意义的。尽管如果您考虑一下,它不会阻止调用者执行observable.source.next(...). 所以这种技术并不能防止 Subject API 泄​​漏,但它确实使它对调用者更加隐藏。

另一方面,对于像TypeScript这样的强类型语言,该方法asObservable()似乎没有多大意义(如果有的话)。静态类型语言通过简单地利用类型系统(例如接口)来解决 API 泄​​漏问题。例如,如果您的getData()方法被定义为返回,Observable<T>那么您可以安全地返回原始Subject的 ,如果尝试调用getData().next()它,调用者将收到编译错误。

想想这个修改过的例子:

let myAPI: { getData: () => Observable<any> }

myAPI = {
    getData: () => {
        const subject = new Subject()
        // ... stuff ...
        return subject
    }
}

myAPI.getData().next() // <--- error TS2339: Property 'next' does not exist on type 'Observable<any>'

当然,由于它最终都会编译为JavaScript,因此可能仍然存在您想要创建委托的情况。但我的观点是,这些情况的空间比使用 vanilla JavaScript时要小得多,并且可能在大多数情况下您不需要该方法。

于 2021-09-08T12:42:33.527 回答