RxJS运营商如何重复"实施?

时间:2018-03-29 12:23:10

标签: javascript typescript rxjs reactive-programming

我正在阅读来自herehere的RxJS中的代码,但这取决于该库的许多其他部分,我无法提取其实现背后的想法。我对它的内部运作方式非常好奇。它如何从头开始重复Observable?例如,这里:

Rx.Observable.of(2, 4, 5, 8, 10)
    .map(num => {
        if(num % 2 !== 0) {
            throw new Error('Odd number');
        }
        return num;
    })
    //Several other operators later...
    .retry(3)
    .subscribe(
        num => console.log(num),
        err => console.log(err.message)
    );

如何知道Observable的开头?

1 个答案:

答案 0 :(得分:1)

重新编辑答案

当前版本的RxJS的相关来源如下:

repeat在此处定义:

https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/repeat.ts

export function repeat<T>(count: number = -1): MonoTypeOperatorFunction<T> {
  return (source: Observable<T>) => {
    if (count === 0) {
      return empty();
    } else if (count < 0) {
      return source.lift(new RepeatOperator(-1, source));
    } else {
      return source.lift(new RepeatOperator(count - 1, source));
    }
  };
}

class RepeatOperator<T> implements Operator<T, T> {
  constructor(private count: number,
              private source: Observable<T>) {
  }
  call(subscriber: Subscriber<T>, source: any): TeardownLogic {
    return source.subscribe(new RepeatSubscriber(subscriber, this.count, this.source));
  }
}

class RepeatSubscriber<T> extends Subscriber<T> {
  constructor(destination: Subscriber<any>,
              private count: number,
              private source: Observable<T>) {
    super(destination);
  }
  complete() {
    if (!this.isStopped) {
      const { source, count } = this;
      if (count === 0) {
        return super.complete();
      } else if (count > -1) {
        this.count = count - 1;
      }
      source.subscribe(this._unsubscribeAndRecycle());
    }
  }
}

此处定义了lift函数:

https://github.com/ReactiveX/rxjs/blob/master/src/internal/Observable.ts

  lift<R>(operator: Operator<T, R>): Observable<R> {
    const observable = new Observable<R>();
    observable.source = this;
    observable.operator = operator;
    return observable;
  }

结论(根据我的谦虚理解,请不要犹豫评论/纠正我)

repeat(n)只是递归地创建相同observable的副本;它只是在完成前一个副本时重新订阅下一个副本。它发出了一个完整的&#39;最后一个完成时的事件。

原始答案

简单回答您的基本问题:

  

如何知道Observable的开头?

没有深入细节,因为它&#34;包装&#34; /&#34;作用于&#34;所有以前的Observables,可以这么说。

实际上,每个操作员都这样做! (在他们身后的整个链条上行动)

不要忘记当你连接/管道操作符时,你会得到一个新的Observable,它从一开始就对应于整个动作。

Observable上的运算符返回一个新的Observable,因此任何应用的新运算符都将应用于这个新的&#34;更大的&#34;可观察到的

Observable1.map(...)返回一个对应于整个流的新Observable2。

Observable2.repeat()重复整个。

编辑

我不是很精明,如果我错了,请提前原谅我,但我想实施的核心在于:

https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/repeatproto.js

是:

observableProto.repeat = function (repeatCount) {
  return enumerableRepeat(this, repeatCount).concat();
};

这似乎意味着它基本上是concat n次相同的可观察量。

repeat(3)concat与自身相同的观察次数的2倍。

let repeated$ = Observable.from([1,2,3]).map(x => x*2).repeat(3);

相当于

let myObs$ = Observable.from([1,2,3]).map(x => x*2);
let repeated$ = myObs.concat(myObs).concat(myObs);