RxJS Observables vs Promise 之簡單對比

最近在學(xué)習(xí)RxJS嘉赎,它是使用 Observables 的響應(yīng)式編程的庫,它使編寫異步或基于回調(diào)的代碼更容易于樟。

下面主要介紹Observables 與 promise的不同點(diǎn)公条。

單值與多值

const numberPromise = new Promise((resolve) => {
    resolve(5);
    resolve(10)
});

numberPromise.then(value => console.log(value));

// 輸出 只會(huì)有 5

下面改寫為observables的寫法,使用 next 替代 promise 的 resolve迂曲, 用subscribe 取代then來訂閱結(jié)果靶橱。

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是可以連續(xù)訂閱的,這個(gè)和promise的區(qū)別很大路捧。平時(shí)我們遇到的可能大多數(shù)都是一個(gè)請求一個(gè)響應(yīng)的這種情況关霸,但是我們也會(huì)存在一些情況:

  • setInterval,需要resolve多個(gè)值
  • 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

代碼執(zhí)行順序

const promise = new Promise((resolve) => {
    console.log('promise call')
    resolve(1);
    console.log('promise end')
})

// 執(zhí)行這段代碼 promise call 和 promise end 會(huì)立即執(zhí)行
const observable = new Observable(() => {
    console.log('I was called!');
});

// 此時(shí)并沒有console

// 只有 observable.subscribe(); 這個(gè)時(shí)候 I was called杰扫!才會(huì)被打印出來队寇。

上面兩段代碼就對比可以發(fā)現(xiàn)Observables是lazy的,只有當(dāng)有人去訂閱(subscribe)的時(shí)候Observables才會(huì)真正的被執(zhí)行章姓。

如果上方setInterval的函數(shù)寫在promise里面佳遣,但是沒有promise.then之類的函數(shù)就會(huì)造成資源的浪費(fèi),而在observable里面凡伊,不訂閱連內(nèi)存都不會(huì)分配零渐。

不能取消 & 能取消

promise默認(rèn)是不能取消的,可以使用promise的實(shí)現(xiàn)庫 bluebird 來實(shí)現(xiàn)系忙。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)

// 結(jié)果

0!
1!
2!
3!

這個(gè)地方需要注意的是, subscribe 返回的不是一個(gè)Observable! 這就是說不能和promise一樣鏈?zhǔn)降膕ubscribe银还。subscribe返回的是一個(gè)對于指定observable的 Subscription风宁。他只有一個(gè)方法可以調(diào)用,就是unsubscribe蛹疯。

單個(gè)訂閱&多個(gè)訂閱

promise 是比較激進(jìn)的杀糯,在一個(gè)promise被創(chuàng)建的時(shí)候,他就已經(jīng)執(zhí)行了苍苞,并且不能重復(fù)的被執(zhí)行了固翰。

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)

// 輸出結(jié)果是 promise call
第一次 hello world 1007
第二次 hello world 5006

上面這個(gè)例子中,我創(chuàng)建了一個(gè)promise羹呵,他是立即執(zhí)行的setTimeout,所以在第一個(gè)then函數(shù)中打印時(shí)間間隔是約等于 1s骂际,這個(gè)是符合我們預(yù)期的,希望能在1s后獲取到promise的返回值 冈欢。 第二個(gè)then函數(shù)是在 5s之后執(zhí)行的歉铝,第二次hello word 和promise的開始時(shí)間差約為5s。因?yàn)樵谠損romise創(chuàng)建的1s后已經(jīng)resolve凑耻,此時(shí)就直接調(diào)用then函數(shù)太示,不會(huì)延時(shí)1s執(zhí)行柠贤。因?yàn)閜romise是只會(huì)執(zhí)行一次。

那么再來看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

這個(gè)就是我們希望的結(jié)果类缤,他在每一次訂閱的時(shí)候都會(huì)重新去執(zhí)行被監(jiān)聽的函數(shù)臼勉,不論什么時(shí)候想要用這個(gè)函數(shù),只需要重新 subscribe 一下就可以餐弱。

用observable已經(jīng)可以實(shí)現(xiàn)多次訂閱宴霸,但是這有時(shí)候可能不能符合我們的業(yè)務(wù)場景,在http請求中膏蚓,我們可能希望只發(fā)一次請求瓢谢,但是結(jié)果被多個(gè)訂閱者共用。 Observables 本身沒有提供這個(gè)功能驮瞧,我們可以用 RxJS 這個(gè)庫來實(shí)現(xiàn)氓扛,它有一個(gè) share 的 operator。

const waitOneSecondObservable = new Observable((observer) => {
    // 發(fā)送http請求
});

const sharedWaitOneSecondObservable = 
    waitOneSecondObservable.share();

sharedWaitOneSecondObservable.subscribe(doSomething);

sharedWaitOneSecondObservable.subscribe(doSomethingElse);

// 使用了share论笔,雖然subscribe了多次幢尚,但是僅發(fā)送一次請求,share了結(jié)果翅楼。

一直是異步 & 可能是異步

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了一個(gè)同步的東西,但他還是會(huì)先執(zhí)行完代碼真慢。

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.');

// 
這個(gè)如果是直接next 5,則輸出是  5毅臊! -> And now we are here.
采用setTimeout next 5, 則相反  And now we are here.-> 5黑界!

promise一直是異步管嬉, Observables則比較靈活,是否為異步得根據(jù)自己的函數(shù)來定朗鸠,這點(diǎn)也比較危險(xiǎn)蚯撩。rxjs中有一些操作符可以讓監(jiān)聽強(qiáng)制為異步的方式,例如 observeOn烛占。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胎挎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子忆家,更是在濱河造成了極大的恐慌犹菇,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芽卿,死亡現(xiàn)場離奇詭異揭芍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卸例,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門称杨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肌毅,“玉大人,你說我怎么就攤上這事姑原⌒” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵页衙,是天一觀的道長摊滔。 經(jīng)常有香客問我,道長店乐,這世上最難降的妖魔是什么艰躺? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮眨八,結(jié)果婚禮上腺兴,老公的妹妹穿的比我還像新娘。我一直安慰自己廉侧,他們只是感情好页响,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著段誊,像睡著了一般闰蚕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上连舍,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天没陡,我揣著相機(jī)與錄音,去河邊找鬼索赏。 笑死盼玄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潜腻。 我是一名探鬼主播埃儿,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼融涣!你這毒婦竟也來了童番?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤威鹿,失蹤者是張志新(化名)和其女友劉穎妓盲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體专普,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悯衬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筋粗。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡策橘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出娜亿,到底是詐尸還是另有隱情丽已,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布买决,位于F島的核電站沛婴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏督赤。R本人自食惡果不足惜嘁灯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望躲舌。 院中可真熱鬧丑婿,春花似錦、人聲如沸没卸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽约计。三九已至诀拭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間煤蚌,已是汗流浹背耕挨。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铺然,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓酒甸,卻偏偏與公主長得像魄健,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子插勤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355