如果您寫 Angular, 那您一定對 Observable 不陌生, 當您對後端做 GET, POST, PUT, DELETE 要求時所使用的 HttpClient 就是 Observable. 因為整個 ReactiveX 非常龐大, 甚至包含了其他程式語言, 這裡我們只簡單的介紹針對 Javascript RxJS 而且在 ngrx/store 常用到的基本定義以及運算子, 完整的 RxJs 請參考 RxJS API
Observable 簡單來說就是資料流, 至於如何產生 Observable 呢? 一般而言有幾種情況
Rx.Observable.of(true);
Rx.Observable.from([1,2,3,4]);
const user = [
{ name: 'John', age: 36},
{ name: 'Jason', age: 24},
{ name: 'Jennifer', age: 33}
]
Rx.Observable.from(user);
Rx.Observable.fromEvent(mouse, 'mousemove');
Rx.Observable.interval(1000);
// getUser from github
function getUser(username) {
return $.ajax({
url: 'https://api.github.com/users/' + username,
dataType: 'jsonp'
}).promise();
}
Rx.Observable.fromPromise(getUser('myname'));
new Rx.Observable(observer => {
observer.next(1);
observer.next(2);
observer.next(3);
setTimeout(() => {
observer.next(4);
observer.complete();
}, 1000);
});
有幾個比較重要的基本定義
public abstract class Subscriber<T> implements Observer<T>, Subscription
用一個例子來說明
const source$ = new Rx.Observable(observer => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.error(new Error('error: error message'));
setTimeout(() => {
observer.next(4);
observer.complete();
}, 1000);
});
source$.subscribe(
val => {
console.log(val);
},
err => {
console.log(err);
},
complete => {
console.log('completed');
}
);
還是覺得很神奇?那我們自己來打造一個簡單的 Observable 好了
var Observable = (function (subscriber) {
this._subscriber = subscriber;
})
Observable.prototype.subscribe = function(next, error, complete) {
this._subscriber(next);
}
const source$ = new Observable(observer => {
observer(1);
observer(2);
observer(3);
});
const subs = source$.subscribe(
(v) => {
console.log('subscribed: ' + v)
},
(err) => {
console.log('error with' + err)
},
(complete) => {
console.log('complete');
}
)
輸出的結果會是
最後談一下 Subject, 因為 ngrx/store 裡的 store 跟 dispatcher 都是 Subject (BehaviorSubject)
Subject 是 Observable 跟 Observer 的延伸, 也就是同時具有 Observable 跟 Observer 的特徵, 他可以被 Subscriber subscribe 也同時 subscribe 到其他的 Observable. 我們可以當它是代理人, 舉個例子
var subject$ = new Rx.Subject();
// acting as Observable
const sub1 = subject$.subscribe({
next: (v) => console.log('observerA: ' + v)
});
const sub2 = subject$.subscribe({
next: (v) => console.log('observerB: ' + v)
});
// acting as Observer
subject$.next(1);
subject$.next(2);
BehaviorSubject
延伸 Subject
再加上它會保留一下最後的一筆資料,也就是即使過了資料產生的時間,後來的訂閱者還是可以拿到最後產生時的資料,也因為如此,在產生新的 BehaviorSubject
時,需要給初值。
如上面例子
var subject$ = new Rx.Subject();
// acting as Observable
const sub1 = subject$.subscribe({
next: (v) => console.log('observerA: ' + v)
});
const sub2 = subject$.subscribe({
next: (v) => console.log('observerB: ' + v)
});
// acting as Observer
subject$.next(1);
subject$.next(2);
const sub3 = subject$.subscribe({
next: (v) => console.log('observerC: ' + v)
});
codepen
sub3 不會得到更新
但是換成 BehaviorSubject
var subject$ = new Rx.BehaviorSubject(0);
// acting as Observable
const sub1 = subject$.subscribe({
next: (v) => console.log('observerA: ' + v)
});
const sub2 = subject$.subscribe({
next: (v) => console.log('observerB: ' + v)
});
// acting as Observer
subject$.next(1);
subject$.next(2);
const sub3 = subject$.subscribe({
next: (v) => console.log('observerC: ' + v)
});
sub3 還是會拿到最後的值 (2),產生 ObservableC: 2
有了 Observable 的基本認識, 接下來我們來談一些運算子 Operators