原文鏈接: https://netbasal.com/rxjs-subjects-for-human-beings-7807818d4e4d
本文為 RxJS 中文社區(qū) 翻譯文章,如需轉(zhuǎn)載,請(qǐng)注明出處,謝謝合作!
如果你也想和我們一起,翻譯更多優(yōu)質(zhì)的 RxJS 文章以奉獻(xiàn)給大家,請(qǐng)點(diǎn)擊【這里】

我已經(jīng)發(fā)表過(guò)一篇關(guān)于 Subject 的文章 (中文),但這次我想嘗試一種不同的方式。
要理解 Subject 是什么的最簡(jiǎn)單的方式就是重新創(chuàng)建一個(gè)。我們來(lái)創(chuàng)建一個(gè)簡(jiǎn)易版的 Subject 。
注意: 下面的示例只是為了闡述概念,還不足以應(yīng)用于實(shí)際開(kāi)發(fā)之中,還有它們并不是 Rx 中 Subjects 的真正完整實(shí)現(xiàn)。
我們來(lái)看看真相。
Subject 既是 Observable,又是 Observer 。
Subject 是 Observable
這表示它擁有所有的操作符 (map、filter,等等) 并且你可以訂閱它。
class MySubject extends Rx.Observable {
constructor() {
super();
}
}
這是第一部分所需的一切了。它可以通過(guò)擴(kuò)展 Observable 類成為 Observable 。
Subject 是 Observer
這表示它必須實(shí)現(xiàn) next(),error() 和 complete() 方法。
class MySubject extends Rx.Observable {
constructor() {
super();
}
next() {}
error() {}
complete() {}
}
好了,我們來(lái)看下一個(gè)真相。
Subject 可以扮演源 observable 和 眾多觀察者之間的橋梁或代理,使得多個(gè)觀察者可以共享同一個(gè) observable 執(zhí)行。
class MySubject extends Rx.Observable {
constructor() {
super();
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
next(value) {
this.observers.forEach(observer => observer.next(value));
}
error(error) {
this.observers.forEach(observer => observer.error(error));
}
complete() {
this.observers.forEach(observer => observer.complete());
}
}
當(dāng)你調(diào)用 subscribe() 方法時(shí),僅僅是將 observer 添加到一個(gè)數(shù)組中。next()、error() 和 completed() 方法會(huì)調(diào)用數(shù)組中每個(gè) observer 的對(duì)應(yīng)方法。
來(lái)使用我們的 Subject 。
const interval$ = Rx.Observable.interval(1000).take(7);
const subject = new MySubject();
subject.map(value => `Observer one ${value}`).subscribe(value => {
console.log(value);
});
interval$.subscribe(subject);
setTimeout(() => {
subject.map(value => `Observer two ${value}`).subscribe(value => {
console.log(value);
});
}, 2000);

當(dāng)使用 Subject 時(shí),無(wú)論你何時(shí) subscribe, 你永遠(yuǎn)都會(huì)得到相同的執(zhí)行,這點(diǎn)不同于典型的 observable,每次 subscribe 都會(huì)開(kāi)啟有個(gè)新的執(zhí)行。(在我們的案例中,這表示你會(huì)有兩個(gè)不相關(guān)的 intervals)
Subject 讓你同享相同的 observable 執(zhí)行
我們來(lái)總結(jié)一下這里發(fā)生了什么。
當(dāng)對(duì) subject 調(diào)用 subscribe 時(shí),只是將 observer 添加到數(shù)組中。
當(dāng) subject 扮演 observer 時(shí),每當(dāng)源 observable (在我們的案例中是指 interval) 發(fā)出值時(shí),它會(huì)調(diào)用數(shù)組中每個(gè) observer 的 next() 方法。
BehaviorSubject
現(xiàn)在讓我們來(lái)嘗試實(shí)現(xiàn) BehaviorSubject 的簡(jiǎn)易版。
我們來(lái)看看真相。
-
BehaviorSubject需要一個(gè)初始值,因?yàn)樗仨毷冀K返回一個(gè)訂閱值,即使它還沒(méi)接收到next()調(diào)用。 - 被訂閱后,它會(huì)返回 subject 的最新值。
- 無(wú)論在任何時(shí)候,你都可以在非 observable 的代碼中使用
getValue()方法來(lái)獲取 subject 的最新值。
class MyBehaviorSubject extends Rx.Observable {
constructor(initialValue) {
super();
this.observers = [];
if (typeof initialValue === 'undefined') {
throw new Error('You need to provide initial value');
}
this.lastValue = initialValue;
}
subscribe(observer) {
this.observers.push(observer);
observer.next(this.lastValue);
}
next(value) {
this.lastValue = value;
this.observers.forEach(observer => observer.next(value));
}
getValue() {
return this.lastValue;
}
}
來(lái)使用我們的 BehaviorSubject 。
const subject = new MyBehaviorSubject('initialValue');
subject.map(value => `Observer one ${value}`).subscribe(function(value) {
console.log(value);
});
subject.next('New value');
setTimeout(() => {
subject.map(value => `Observer two ${value}`).subscribe(function(value) {
console.log(value);
});
}, 2000);

ReplaySubject
現(xiàn)在讓我們來(lái)嘗試實(shí)現(xiàn) ReplaySubject 的簡(jiǎn)易版。
我們來(lái)看看真相.
-
ReplaySubject表示一個(gè)對(duì)象既是 observable 序列,又是 observer 。 - 每次通知都會(huì)廣播給所有已經(jīng)訂閱和未來(lái)的 observers,observers 會(huì)遵循緩沖調(diào)整策略。
class MyReplaySubject extends Rx.Observable {
constructor(bufferSize) {
super();
this.observers = [];
this.bufferSize = bufferSize;
this.lastValues = [];
}
subscribe(observer) {
this.lastValues.forEach(val => observer.next(val));
this.observers.push(observer);
}
next(value) {
if (this.lastValues.length === this.bufferSize) {
this.lastValues.shift();
}
this.lastValues.push(value);
this.observers.forEach(observer => observer.next(value));
}
}
來(lái)使用我們的 ReplaySubject 。
const subject = new MyReplaySubject(3);
subject.next('One');
subject.next('Two');
subject.next('Three');
subject.next('Four');
setTimeout(() => {
subject.map(value => `Later Observer ${value}`).subscribe(function(value) {
console.log(value);
});
}, 2000);

何時(shí)使用 Subject
- 需要共享相同的 observable 執(zhí)行。
- 當(dāng)需要決定觀察者遲來(lái)時(shí)該怎么做,是否使用
ReplaySubject、BehaviorSubject? - 需要完全控制
next()、error()和completed()方法。
在 Medium 或 Twitter 關(guān)注我,以閱讀更多 Angular、Vue 和 JS 相關(guān)內(nèi)容!