学习一个库最好的方法就是看其源码,理解其 api
的调用原理,用起来自然也就很清楚自己到底在干什么了,秉持着此观念,为了更好地理解 rxjs
,抽空将其源码看了一遍
本系列文章不会刻意涉及概念性的东西,主线就是解读源码,并在恰当的时候给出一些小例子,源码基于 rxjs v7.4.0
版本
从 new Observable
开始
import { Observable } from 'rxjs'
const observable = new Observable<number>(subscriber => {subscriber.next(1)subscriber.next(2)subscriber.complete()
})
observable.subscribe({next: data => console.log('next data:', data),complete: () => {console.log('complete')}
})
输出如下:
// 开始输出
next data: 1
next data: 2
complete
// 结束输出
通过 new Observable()
方法创建了一个可观察对象 observable
,然后通过 subscribe
方法订阅这个observable
,订阅的时候会执行在 new Observable
时候传入的函数参数,那么就来看下 new Observable
到底做了什么
// /src/internal/Observable.ts
export class Observable<T> implements Subscribable<T> {// ...constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {if (subscribe) {this._subscribe = subscribe;}}// ...
}
Observable
的初始化方法很简单,就是将回调函数绑定到实例的 _subscribe
属性上
subscribe
Observable
实现 (implements
) 了 Subscribable
(订阅)接口
// /src/internal/types.ts
export interface Subscribable<T> {subscribe(observer: Partial<Observer<T>>): Unsubscribable;
}
这个 subscribe
正是下一步要用于订阅的方法,在当前版本中 subscribe
的方法签名有三个,三个只是传参形式不同,最终都会处理成相同的对象,着重看第一个
subscribe(observer?: Partial<Observer<T>>): Subscription;
对于第一个签名,接收的参数与Observer
接口相关,这个接口有三个方法属性
export interface Observer<T> {next: (value: T) => void;error: (err: any) => void;complete: () => void;
}
subscribe
可以是一个对象,这个对象包含三个方法属性 next
、error
、complete
,当你不关心 error
和 complete
这两个属性的时候,那么可以按照第二个函数签名直接传入一个方法,这个方法就默认代表 next
方法属性
进入 subscribe
方法
subscribe(observerOrNext?: Partial<Observer<T>> | ((value: T) => void) | null,error?: ((error: any) => void) | null,complete?: (() => void) | null
): Subscription {const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);errorContext(() => {// ...});return subscriber;
}
subscribe
的第一个参数可以是一个 subscriber
(具有 next
、error
、complete
三个属性,所以类型合法),不过这种传参形式一般都是库内部使用,我们正常写法还是传入一个纯粹的对象或者方法,那么就意味着会执行 new SafeSubscriber(observerOrNext, error, complete)
// node_modules/rxjs/src/internal/Subscriber.ts
export class SafeSubscriber<T> extends Subscriber<T> {// ...
}