携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
Subject
Subject是一个多播的Observable,每个Subject既是一个Observable可观察对象,又是一个Observer观察者,所以Subject有subscribe方法,继承自Observable,也有next,error,complete方法,继承自Subscription。先来看一下Subject的源码部分吧。
export class Subject<T> extends Observable<T> implements SubscriptionLike {
closed = false;
private currentObservers: Observer<T>[] | null = null;
observers: Observer<T>[] = [];
constructor() {
// NOTE: This must be here to obscure Observable's constructor.
super();
}
next(value: T) {
errorContext(() => {
this._throwIfClosed();
if (!this.isStopped) {
if (!this.currentObservers) {
this.currentObservers = Array.from(this.observers);
}
for (const observer of this.currentObservers) {
observer.next(value);
}
}
});
}
error(err: any) {
errorContext(() => {
this._throwIfClosed();
if (!this.isStopped) {
this.hasError = this.isStopped = true;
this.thrownError = err;
const { observers } = this;
while (observers.length) {
observers.shift()!.error(err);
}
}
});
}
complete() {
errorContext(() => {
this._throwIfClosed();
if (!this.isStopped) {
this.isStopped = true;
const { observers } = this;
while (observers.length) {
observers.shift()!.complete();
}
}
});
}
unsubscribe() {
this.isStopped = this.closed = true;
this.observers = this.currentObservers = null!;
}
asObservable(): Observable<T> {
const observable: any = new Observable<T>();
observable.source = this;
return observable;
}
}
Subject有一个共有属性observers,存储所有的observer观察者。还有next,error,complete,unsubscribe,asObservable等,这些都是我们要实现的。这些的基本功能这里就不再回顾了,不熟悉的小伙伴可以看我之前的几篇文章哦。
开始写代码。这里的实现和源码是有些不同的,源码里的Subject是要继承Observable的,这里简化了这个实现,所以asObservable的实现也不一样。一切从简,先实现一个基础版的Subject,但是这些基本功能都是会有的,后续可能会继续在实现一版更接近源码的实现。
class Subject {
closed = false;
observers = [];
constructor(){
}
next(data){
if (!this.closed) {
this.observers.forEach((subscriber) => {
subscriber.next(data);
});
}
}
error(error){
if (!this.closed) {
this.observers.forEach((subscriber) => {
subscriber.error(error);
});
}
this.closed = true;
this.observers = [];
}
complete(){
if (!this.closed) {
this.observers.forEach((subscriber) => {
subscriber.complete();
});
}
this.closed = true;
this.observers = [];
}
subscribe(observer) {
let subscriber = new SafeSubscriber(observer);
this.observers.push(subscriber);
return subscriber;
}
unsubscribe(){
this.closed = true;
this.observers = [];
}
asObservable(){
return new Observable((observer) => {
this.subscribe({
next(data){
observer.next(data);
},
error(error){
observer.error(error);
},
complete(){
observer.complete();
}
});
});
}
}
BehaviorSubject
实现了Subject,再来实现BehaviorSubject就容易的多了,BehaviorSubject一旦有订阅会发出上一次的值。开始撸代码哦。
class BehaviorSubject {
closed = false;
observers = [];
constructor(value){
this._value = value;
}
next(value){
if (!this.closed) {
this.observers.forEach((subscriber) => {
subscriber.next(value);
});
this._value = value;
}
}
error(error){
if (!this.closed) {
this.observers.forEach((subscriber) => {
subscriber.error(error);
});
}
this.closed = true;
this.observers = [];
}
complete(){
if (!this.closed) {
this.observers.forEach((subscriber) => {
subscriber.complete();
});
}
this.closed = true;
this.observers = [];
}
subscribe(observer) {
let subscriber = new SafeSubscriber(observer);
this.observers.push(subscriber);
subscriber.next(this._value);
return subscriber;
}
unsubscribe(){
this.closed = true;
this.observers = [];
}
asObservable(){
return new Observable((observer) => {
this.subscribe({
next(data){
observer.next(data);
},
error(error){
observer.error(error);
},
complete(){
observer.complete();
}
});
});
}
}
总结
我们实现了Observable,asyncScheduler,部分操作符,还有Subject,BehaviorSubject,尽管还比较简陋,但是大体功能是可以工作的。最后把自己的Rxjs库导出就可以使用了。
module.exports = {
Observable,
map,
of,
asyncScheduler,
interval,
Subject,
BehaviorSubject
};
测试一下代码,看看有没有什么问题。
const { Subject, BehaviorSubject, Observable, map, of, asyncScheduler, interval } = require("./rxjs.js");
const source$ = new Observable((observer) => {
observer.next(1);
observer.next(2);
observer.complete();
observer.next(3);
});
let subscription1 = source$.pipe(map((data) => data * 2), map((data) => data + 1)).subscribe({
next(data){
console.log(data);
},
error(error){
console.log('error', error);
},
complete(){
console.log('complete');
}
});
let subscription2 = source$.subscribe({
next(data){
console.log(data);
}
});
let s2$ = of(2,7,9);
s2$.subscribe((data) => {
console.log(data);
});
asyncScheduler.schedule(() => {
console.log('我是异步调度器');
}, 2000);
let s3$ = interval(1000);
let subscription3 = s3$.subscribe((data) => {
console.log(data);
});
setTimeout(() => {
subscription3.unsubscribe();
},5000);
let s1$ = new Subject();
let sub1 = s1$.subscribe((data) => {
console.log("第一个订阅:", data);
});
s1$.next(1);
s1$.subscribe((data) => {
console.log("第二个订阅:", data);
});
s1$.next(2);
let s4$ = s1$.asObservable();
s4$.subscribe((data) => {
console.log("asObservable:", data);
});
s4$.next(3);
let bs$ = new BehaviorSubject(666);
bs$.next('888');
bs$.subscribe((data) => {
console.log(1, data);
});
bs$.subscribe((data) => {
console.log(2, data);
});
bs$.next('999');
bs$.asObservable().subscribe((data) => {
console.log(3, data);
});
console.log('End');
居然可以完美运行,哈哈哈。 Rxjs的源码部分就到此为止了,后续根据情况在做进一步的深化学习哦,但是不要忘了学以致用,多多使用才能体会Rxjs的神奇强大之处。