使用自定义功能扩展Observable

时间:2017-06-16 23:36:08

标签: rxjs rxjs5

我的情况:我有一个数据存储区,在那里我可以获得可以使用RxJS Observables观察到的模型。一般类型签名是

const foo = new Model({id: 123}, dataStore);
foo.asObservable().subscribe((v) => /* do stuff with values of this model */ );

一般的概念是,像observables这样的数据处理有两个方面的帮助:(a)当你有一个冷缓存情况时(比如浏览器的localStorage有一些过时的数据)但仍想显示某些东西正在获取实际数据,以及(b)当您已经加载了正确的数据时,无论是在本地还是在需要传播的后端进行更改。到目前为止,这种方法运作良好。

下一个问题是模型与其他模型有关系(例如,父母有很多孩子)。按照惯例,我可以做像

这样的事情
foo.asObservable().subscribe(v => console.log(v.relationships.children))

和(在这里忽略空错误),我最初得到[1,2,3],然后在父子关系中添加4时得到[1,2,3,4]。和我一起到目前为止?

问题是我经常想要访问这些孩子,而不是作为索引,而是作为可观察的模型(因此我可以显示用户社区的所有成员的名字,例如,两者都是社区和所有成员都是数据模型)。我目前正在使用我的控制器代码中的大量样板文件执行此操作,涉及对.combineLatest的大量调用。

我想要做的是为这种类型的对象定义一个自定义操作符,这样我就可以将它们整合在一起。理想情况下它看起来像:

foo.asObservable().inflateRelationship('members').subscribe(
  (v) => // v === [{name: 'steve'}, {name: 'gertude'} ...] etc
);

我实际上这部分工作,但问题是开始实际链。我正在关注instructions for extending Observable,创建一个实现lift的新CustomObservable类,但我的问题是我不能在这里使用静态Observable方法,比如Observable.merge()来生成我的初始值在Model.asObservable中可观察到。

我的问题来了:

const preload$ = Observable... 
  // create the "load from cache and backend observable"
const update$ = Observable ... 
  // create the "update after load when the storage updates observable" 

return new CustomObservable(context).merge(preload$, update$);

这是失败的最后一行。我想在两个常规可观察流上返回由合并运算符生成的CustomObservable。我需要在那里向构造函数添加上下文,因为该上下文包含对实际膨胀子模型所需的数据存储的引用(没有它,id数组流是没有意义的。)

这就是我的具体问题:我创建了一个Observable运算符,我想将它作为一个类添加到CustomObservable中,所以我可以像普通的那样使用下游运算符,但我似乎无法正确获取整个链拉开了序幕。

任何指针,即使是正确(和非平凡)扩展Observable类的现有项目也是受欢迎的。我试着深入挖掘源代码,但我甚至无法想出那部分内容(看起来Observable类静态在其他地方被添加了,而且乍一看是多么不清楚,因为{{3}中没有定义})。

1 个答案:

答案 0 :(得分:4)

这是其中之一"写一个很长的问题来叠加溢出并在你发布它之后不久找出答案"有点情况,但我想我只是为了后人而写出答案。

假设您已按照说明操作子类操作员,您所做的就是

asObservable() {
  // do a bunch of stuff making different things
  return Observable.merge(one$, two$)
    .let(obs => new CustomObservable(context, obs);

然后在CustomObservable中你有

class CustomObservable extends Observable {
  constructor(context, source) {
    super();
    this.source = source;
  }
  customOperator() {}
  lift(operator) {
    const obs = new CustomObservable(context, this);
    obs.operator = operator;
    return obs;
  }
}

这让我做

Model.asObservable()
.filter() // normal RxJs operator here
.customOperator() // yay
.map() // back to other RxJs operators
.subscribe(v => console.log(v)) // or whatever

所以,是的。现在我的角度模型可以看起来更多。