携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
工作中使用Angular开发项目,对Rxjs有一定的熟悉和理解,但是感觉从理解上还觉得有些地方理解的不够深入和透彻。首先需要整体上去学一下Rxjs,了解一下前因后果,对Rxjs的进阶还是很有帮助的。想进阶精通一个库的最好办法就是学习它的源码,学了源码后,API使用起来才能更加得心应手。
我从整体上过了一下Rxjs的主要代码,而且很多细节我都没有去考虑,也就是先范读,从整体上把它串一下,下一步可以再去精读。本文就是第一步,先范读,而且基于范读会手写一个简版的Rxjs,虽然简陋,但是可以实现Rxjs的基本功能的。源码学习是基于Rxjs 7.5.5。
我们先从几个核心概念来一点点学习。
Observable
我们先来看一下通过new创建的Observable。
const { Observable } = require('rxjs');
const source$ = new Observable((observer) => {
observer.next(1);
observer.next(2);
observer.complete();
});
let subscription1 = source$.subscribe({
next(data){
console.log(data);
},
error(error){
console.log('error');
},
complete(){
console.log('complete');
}
});
console.log('End');
输出:
1
2
complete
End
首先通过new Observable创建了一个可观察对象,然后通过subscribe方法订阅了一下,订阅后就会执行new Observable时传入的函数参数。
总结一下:
- Observable是一个构造函数,构造函数里有一个函数作为参数,这个函数参数里有一个参数observer对象,这个对象有next,error,complete等方法;
- 可观察对象Observable有一个subscribe方法,subscribe方法有一个参数,这个参数可以是一个object对象,也可以是一个函数;
有了上面的两点总结,一会就可以先把代码框架搭建起来了。继续之前,先看下源码里的Observable类。
export class Observable<T> implements Subscribable<T> {
/**
* @constructor
* @param {Function} subscribe the function that is called when the Observable is
* initially subscribed to. This function is given a Subscriber, to which new values
* can be `next`ed, or an `error` method can be called to raise an error, or
* `complete` can be called to notify of a successful completion.
*/
constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {
if (subscribe) {
this._subscribe = subscribe;
}
}
...
}
在来看一下订阅函数subscribe。subscribe方法签名有多个,只是传参形式不同。
export class Observable<T> implements Subscribable<T> {
...
subscribe(observer?: Partial<Observer<T>>): Subscription;
subscribe(next: (value: T) => void): Subscription;
subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;
}
对于参数observer,它和Observer接口相关,这个接口有三个属性:
export interface Observer<T> {
next: (value: T) => void;
error: (err: any) => void;
complete: () => void;
}
subscribe方法的参数,可以是一个对象,这个对象有三个属性,next,error,complete,也可以是一个函数,也就是next。
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(() => {
const { operator, source } = this;
subscriber.add(
operator
? // We're dealing with a subscription in the
// operator chain to one of our lifted operators.
operator.call(subscriber, source)
: source
? // If `source` has a value, but `operator` does not, something that
// had intimate knowledge of our API, like our `Subject`, must have
// set it. We're going to just call `_subscribe` directly.
this._subscribe(subscriber)
: // In all other cases, we're likely wrapping a user-provided initializer
// function, so we need to catch errors and handle them appropriately.
this._trySubscribe(subscriber)
);
});
return subscriber;
}
subscribe的参数,可能是只有next和error的对象,但是我们期望它是有next,error和complete的,所以我们要把它补全,方便后续的操作。因此,就在把这个参数封装一下,也就是new SafeSubscriber(...) 。
export class SafeSubscriber<T> extends Subscriber<T> {
constructor(
observerOrNext?: Partial<Observer<T>> | ((value: T) => void) | null,
error?: ((e?: any) => void) | null,
complete?: (() => void) | null
) {
super();
let partialObserver: Partial<Observer<T>>;
if (isFunction(observerOrNext) || !observerOrNext) {
partialObserver = {
next: observerOrNext ?? undefined,
error: error ?? undefined,
complete: complete ?? undefined,
};
} else {
...
partialObserver = {
next: observerOrNext.next && bind(observerOrNext.next, context),
error: observerOrNext.error && bind(observerOrNext.error, context),
complete: observerOrNext.complete && bind(observerOrNext.complete, context),
};
}
...
}
}
SafeSubscriber的主要作用是对next,error,complete三个属性进行了一层封装。判断了observerOrNext是否为函数,如果是函数则它就是next函数,如果不是函数,那它就是一个object对象。
另外的话,还需要考虑unsubscribe取消订阅,需要维护一个是否closed的状态,等被取消订阅的时候,就把这状态置为true,当取消订阅,error,或者complete的时候,都需要改变一下这个状态。
好了,已经梳理了差不多了,我们只关注了高层级的代码逻辑,至于具体细节实现暂时先忽略。
启动手写部分哦。
class SafeSubscriber {
constructor(subscriber) {
this.closed = false;
this.next = (data) => {
if (!this.closed) {
if (typeof subscriber === 'function') {
subscriber(data);
}
else {
subscriber.next(data);
}
}
};
this.error = (error) => {
subscriber.error && subscriber.error(error);
this.closed = true;
};
this.complete = () => {
subscriber.complete && subscriber.complete();
this.closed = true;
};
this.unsubscribe = () => {
this.closed = true;
};
}
}
class Observable {
constructor(subscribe){
this._subscribe = subscribe;
}
subscribe(observer) {
let subscriber = new SafeSubscriber(observer);
try {
this._subscribe(subscriber);
}
catch(error){
subscriber.error(error);
}
return subscriber;
}
}
可以测试一下,发现没有问题哦。虽然功能还比较初级,但是可以正常工作,离Rxjs又近了一步,后续文章会继续学原理哦。