最近在學習RxJS,它是使用 Observables 的響應式編程的庫,它使編寫異步或基於回調的代碼更容易。web
下面主要介紹Observables 與 promise的不一樣點。編程
const numberPromise = new Promise((resolve) => {
resolve(5);
resolve(10)
});
numberPromise.then(value => console.log(value));
// 輸出 只會有 5
複製代碼
下面改寫爲observables的寫法,使用 next 替代 promise 的 resolve, 用subscribe 取代then來訂閱結果。promise
const Observable = require('rxjs/Observable').Observable;
const numberObservable = new Observable((observer) => {
observer.next(5);
observer.next(10);
});
numberObservable.subscribe(value => console.log(value));
// 輸出 5 10
複製代碼
observable是能夠連續訂閱的,這個和promise的區別很大。平時咱們遇到的可能大多數都是一個請求一個響應的這種狀況,可是咱們也會存在一些狀況:bash
const numberObservable = new Observable((observer) => {
let i = 0;
setInterval(() => {
observer.next(i++);
}, 1000);
});
numberObservable.subscribe(value => console.log(value));
// 輸出 0 1 2 3 4 5
複製代碼
const promise = new Promise((resolve) => {
console.log('promise call')
resolve(1);
console.log('promise end')
})
// 執行這段代碼 promise call 和 promise end 會當即執行
const observable = new Observable(() => {
console.log('I was called!');
});
// 此時並無console
// 只有 observable.subscribe(); 這個時候 I was called!纔會被打印出來。
複製代碼
上面兩段代碼就對比能夠發現Observables是lazy的,只有當有人去訂閱(subscribe)的時候Observables纔會真正的被執行。異步
若是上方setInterval的函數寫在promise裏面,可是沒有promise.then之類的函數就會形成資源的浪費,而在observable裏面,不訂閱連內存都不會分配。函數
promise默認是不能取消的,可使用promise的實現庫 bluebird 來實現。bluebird是徹底兼容promise而且添加了一些有用的方法。學習
const Observable = require('rxjs/Observable').Observable;
const observable = new Observable((observer) => {
let i = 0;
const token = setInterval(() => {
observer.next(i++);
}, 1000);
return () => clearInterval(token);
});
const subscription = observable.subscribe(value => console.log(value + '!'));
setTimeout(() => {
subscription.unsubscribe();
}, 5000)
// 結果
0!
1!
2!
3!
複製代碼
這個地方須要注意的是, subscribe 返回的不是一個Observable! 這就是說不能和promise同樣鏈式的subscribe。subscribe返回的是一個對於指定observable的 Subscription。他只有一個方法能夠調用,就是unsubscribe。ui
promise 是比較激進的,在一個promise被建立的時候,他就已經執行了,而且不能重複的被執行了。spa
let time;
const waitOneSecondPromise = new Promise((resolve) => {
console.log('promise call')
time = new Date().getTime();
setTimeout(() => resolve('hello world'), 1000);
});
waitOneSecondPromise.then((value) => {console.log( '第一次', value, new Date().getTime() - time)});
setTimeout(() => {
waitOneSecondPromise.then((value) => {console.log('第二次', value, new Date().getTime() - time)});
}, 5000)
// 輸出結果是 promise call
第一次 hello world 1007
第二次 hello world 5006
複製代碼
上面這個例子中,我建立了一個promise,他是當即執行的setTimeout,因此在第一個then函數中打印時間間隔是約等於 1s,這個是符合咱們預期的,但願能在1s後獲取到promise的返回值 。 第二個then函數是在 5s以後執行的,第二次hello word 和promise的開始時間差約爲5s。由於在該promise建立的1s後已經resolve,此時就直接調用then函數,不會延時1s執行。由於promise是隻會執行一次。code
那麼再來看obsrvables
const Observable = require('rxjs/Observable').Observable;
let time;
const waitOneSecondObservable = new Observable((observer) => {
console.log('I was called');
time = new Date().getTime();
setTimeout(() => observer.next('hey girl'), 1000);
});
waitOneSecondObservable.subscribe((value) => {console.log( '第一次', value, new Date().getTime() - time)});
setTimeout(() => {
waitOneSecondObservable.subscribe((value) => {console.log( '第二次', value, new Date().getTime() - time)});
}, 5000)
// 輸出
I was called
第一次 hey girl 1003
I was called
第二次 hey girl 1003
複製代碼
這個就是咱們但願的結果,他在每一次訂閱的時候都會從新去執行被監聽的函數,不論何時想要用這個函數,只須要從新 subscribe 一下就能夠。
用observable已經能夠實現屢次訂閱,可是這有時候可能不能符合咱們的業務場景,在http請求中,咱們可能但願只發一次請求,可是結果被多個訂閱者共用。 Observables 自己沒有提供這個功能,咱們能夠用 RxJS 這個庫來實現,它有一個 share 的 operator。
const waitOneSecondObservable = new Observable((observer) => {
// 發送http請求
});
const sharedWaitOneSecondObservable =
waitOneSecondObservable.share();
sharedWaitOneSecondObservable.subscribe(doSomething);
sharedWaitOneSecondObservable.subscribe(doSomethingElse);
// 使用了share,雖然subscribe了屢次,可是僅發送一次請求,share告終果。
複製代碼
const promise = new Promise((resolve) => {
resolve(5);
});
promise.then(value => console.log(value + '!'));
console.log('And now we are here.');
//
And now we are here.
5!
複製代碼
雖然在promise裏面 resolve了一個同步的東西,但他仍是會先執行完代碼。
const Observable = require('rxjs/Observable').Observable;
const observable = new Observable((observer) => {
// observer.next(5);
setTimeout(() => {
observer.next(5);
})
});
observable.subscribe(value => console.log(value + '!'));
console.log('And now we are here.');
//
這個若是是直接next 5,則輸出是 5! -> And now we are here.
採用setTimeout next 5, 則相反 And now we are here.-> 5!
複製代碼
promise一直是異步, Observables則比較靈活,是否爲異步得根據本身的函數來定,這點也比較危險。rxjs中有一些操做符可讓監聽強制爲異步的方式,例如 observeOn。