RxJS Observables vs Promise 之簡單對比

最近在學習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

  • setInterval,須要resolve多個值
  • webSockets
  • DOM events
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。

相關文章
相關標籤/搜索