rxjs subscribe原理

1,542 阅读3分钟

目录:

  • 一.raw Observable's subscrbe
  • 二.piped Observable's subscrbe?

正文:

一.raw Observable's subscrbe

我们把of,from,interval这些没有经过操作符处理的Observable成为raw Observable,它的subscribe()是最简单的被订阅

const nextObsever = i => console.log(i);
of(1).subscribe(nextObsever);
// output: 1

这里被订阅指的是nextObsever作为订阅者,of(1)作为发布者,of()在内部调用了fromArray(),它定义在rxjs/src/internal/observable/fromArray.ts:

export function fromArray<T>(input: ArrayLike<T>, scheduler?: SchedulerLike) {
  if (!scheduler) {
    return new Observable<T>(subscribeToArray(input));
  } else {
    return scheduleArray(input, scheduler);
  }
}

从上面我们可以看到:

  • raw Observable通常还可以接收第二个参数,它是一种scheduler,用来控制发布者发布的时机,就像js里面的setTimeout, setInterval之类的

  • subscribeToArray()接收of()的入参作为自己的入参,并返回一个函数,它定义在rxjs/src/internal/util/subscribeToArray.ts:

    export const subscribeToArray = <T>(array: ArrayLike<T>) => (subscriber: Subscriber<T>) => {
        for (let i = 0, len = array.length; i < len && !subscriber.closed; i++) {
            subscriber.next(array[i]);
        }
        subscriber.complete();
    };
    

    返回的函数(暂且称作rt)将接收一个subscriber对象,然后将of()的入参通过该对象的next接口传递给subscriber,这个Subscriber实际上是Observer的增强版,定义在rxjs/src/internal/Subscriber.ts:

    export class Subscriber<T> extends Subscription implements Observer<T> {
    
  • Subscriber不像Observer那样对外开放标准,它是在内部用来处理subscribe这个方法的参数,我们都知道subscribe方法接收两种形式的传参:

    // 1.
    of(1).subscribe(
        () => {}, // next
        () => {}, // error
        () => {} // complete
    );
    // 2.
    of(1).subscribe({
        next() {
            
        },
        error() {
    
        },
        complete() {
    
        }
    });
    

    如果是第二种传参,rt函数直接接收一个obsever就行了,但是对第一种传参就不行了,所以subscriber是对两种传参进行了处理之后的对象,它将第一种参数转换成了第二种参数的形式

  • 具体的转换过程发生在subscribe()执行的时候:

    subscribe(observerOrNext?: PartialObserver<T> | ((value: T) => void),
                error?: (error: any) => void,
                complete?: () => void): Subscription {
    
        const { operator } = this;
        const sink = toSubscriber(observerOrNext, error, complete);
    
        if (operator) {
        sink.add(operator.call(sink, this.source));
        } else {
        sink.add(
            this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?
            this._subscribe(sink) :
            this._trySubscribe(sink)
        );
        }
    
        if (config.useDeprecatedSynchronousErrorHandling) {
        if (sink.syncErrorThrowable) {
            sink.syncErrorThrowable = false;
            if (sink.syncErrorThrown) {
            throw sink.syncErrorValue;
            }
        }
        }
    
        return sink;
    }
    

    可以看到传入的observerOrNext有两种可能,toSubscriber实现了整个转化统一的过程,为了不丢失主线,转化的过程在这里就不详细讲了。

    现在sink已经是一个subscriber了,它的next方法指向我们传入的observerOrNext,此时我们只需要把sink传入rt,就可以完成整个消息传递的过程

  • raw Observable是没有operator的,所以上面实际执行了this._subscribe(sink),这个this._subscribe在我们实例化Observable的时候指向了rt:

    constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {
        if (subscribe) {
            this._subscribe = subscribe;
        }
    }
    

    这里要注意,Observable自己定义了默认的__subscribe(),如果我们调用subscribe(nextFn)时传了nextFn,则它会覆盖默认的__subscribe()

    至此整个消息传递的过程的就完成了,但这只是rxjs里面最简单的被订阅,了解它的基本原理之后,接下来去理解操作符的被订阅就很easy了

二.piped Observable's subscrbe?

未完待续...