[譯] RxJS Observable 與 Promises 和 Async-Await 交互

原文鏈接: https://medium.com/@benlesh/rxjs-observable-interop-with-promises-and-async-await-bebb05306875
本文為 RxJS 中文社區(qū) 翻譯文章松邪,如需轉載痰洒,請注明出處出爹,謝謝合作!
如果你也想和我們一起核畴,翻譯更多優(yōu)質的 RxJS 文章以奉獻給大家,請點擊【這里】

async-fun-77-638.jpg

不時地會有人問我關于如何與 RxJS 配合使用 async 函數(shù)或 promises冲九,還有更糟的谤草,我被告之“事實”的真相是 async-await 和 Observables 并不能“在一起使用”。RxJS 從一開始就具備與 Promises 的高度互操作性莺奸。希望這篇文章能對此有所啟發(fā)丑孩。

如果可以接收 Observable,就可以接收 Promise

例如灭贷,如果使用 switchMap温学,你可以返回 Promise 來替代,就像返回 Observable 那樣甚疟。以下這些都是有效的:

// Observable: 每1秒發(fā)出自增數(shù)值乘以100仗岖,共發(fā)出10次
const source$ = Observable.interval(1000)
  .take(10)
  .map(x => x * 100);
/**
 * 返回 promise,它等待 `ms` 毫秒并發(fā)出 "done" 
 */
function promiseDelay(ms) {
  return new Promise(resolve => {
    setTimeout(() => resolve('done'), ms);
  });
}

// 在 switchMap 中使用 promiseDelay
source$.switchMap(x => promiseDelay(x)) // 正常運行
  .subscribe(x => console.log(x)); 

source$.switchMap(promiseDelay) // 更簡潔了
  .subscribe(x => console.log(x)); 

// 或者使用 takeUntil
source$.takeUntil(doAsyncThing('hi')) // 完全可以運行
  .subscribe(x => console.log(x))

// 或者類似這樣的奇怪組合
Observable.of(promiseDelay(100), promiseDelay(10000)).mergeAll()
  .subscribe(x => console.log(x))

使用 defer 使得返回 Promise 的函數(shù)可以重試

如果你可以訪問創(chuàng)建 promise 的函數(shù)览妖,你可以使用 Observable.defer() 來包裝它轧拄,以使 Observable 可以在報錯時進行重試。

function getErroringPromise() {
  console.log('getErroringPromise called');
  return Promise.reject(new Error('sad'));
}

Observable.defer(getErroringPromise)
  .retry(3)
  .subscribe(x => console.log);

// 輸出 "getErroringPromise called" 4次 (開始1次 + 3次重試), 然后報錯

使用 defer() 定義使用 async-await 的 Observable

事實證明讽膏, defer 是個非常強大的小工具紧帕。你可以使用它,基本上是直接使用 async 函數(shù)桅打,它會創(chuàng)建一個發(fā)出返回值及完成的 Observable 是嗜。

Observable.defer(async function() {
  const a = await promiseDelay(1000).then(() => 1);
  const b = a + await promiseDelay(1000).then(() => 2);
  return a + b + await promiseDelay(1000).then(() => 3);
})
.subscribe(x => console.log(x)) // 輸出 7

使用 forEach 訂閱 Observable 以在 async-await 中創(chuàng)建并發(fā)任務

這是 RxJS 中較少使用的功能,它來自 TC39 Observable 提議挺尾。訂閱 Observable 可不止一種方式鹅搪! subscribe 是訂閱 Observable 的傳統(tǒng)方式,它返回用來取消數(shù)據(jù)流的 Subscription 對象遭铺。而 forEach 以一種不可取消的方式來訂閱 Observable 丽柿,它接收一個函數(shù)用于每個值恢准,并返回 Promise,該 Promise 體現(xiàn)了 Observable 的完成和錯誤路徑甫题。

const click$ = Observable.fromEvent(button, 'click');
/**
 * 等待10次按鈕點擊馁筐,然后使用 fetch 將第10次點擊的時間戳發(fā)送給端點
 */
async function doWork() {
  await click$.take(10)
    .forEach((_, i) => console.log(`click ${i + 1}`));
  return await fetch(
    'notify/tenclicks',
    { method: 'POST', body: Date.now() }
  );
}

使用 toPromise() 和 async/await 將 Observable 最后發(fā)出的值作為 Promise 發(fā)出

toPromise 函數(shù)實際上是有些巧妙的,因為它并不是真正的“操作符”坠非,而是以一種 RxJS 特定的方式來訂閱 Observable 并將其包裝成一個 Promise 敏沉。一旦 Observable 完成,Promise 便會 resolve Observable 最后發(fā)出的值炎码。這意味著如果 Observable 發(fā)出值 “hi” 然后等待10秒才完成盟迟,那么返回的 Promise 會等待10秒才 resolve “hi” 。如果 Observable 一直不完成潦闲,那么 Promise 便永遠不會 resolve 攒菠。

注意: 使用 toPromise() 是一種反模式,除非當你正在處理預期為 Promise 的 API歉闰, 比如 async-await

const source$ = Observable.interval(1000).take(3); // 0, 1, 2
// 等待3秒辖众,然后輸出 "2"
// 因為 Observable 需要3秒才能完成,而 interval 發(fā)出從0開始自增的數(shù)字
async function test() {
  console.log(await source$.toPromise());
}

Observables 和 Promises 能很好地一起使用

不可否認地和敬,如果你的目標是響應式編程赵辕,那么大多數(shù)時間里你可能想要使用 Observable ,但是 RxJS 嘗試去盡可能地滿足大眾需求概龄,畢竟當下 Promises 還是很受歡迎的还惠。此外,在 async 函數(shù)中使用 RxJS Observables 和 forEach私杜,為管理并發(fā)性和在 async-await 中“只能正常運行”的任務開啟了大量有趣的可能性蚕键。

想學習更多 RxJS 知識, 我可以親自教學或選擇在線學習衰粹,盡在http://rxworkshop.com!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末锣光,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子铝耻,更是在濱河造成了極大的恐慌誊爹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓢捉,死亡現(xiàn)場離奇詭異频丘,居然都是意外死亡,警方通過查閱死者的電腦和手機泡态,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門搂漠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來某弦,“玉大人桐汤,你說我怎么就攤上這事而克。” “怎么了怔毛?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵员萍,是天一觀的道長。 經常有香客問我拣度,道長碎绎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任蜡娶,我火速辦了婚禮,結果婚禮上映穗,老公的妹妹穿的比我還像新娘窖张。我一直安慰自己,他們只是感情好蚁滋,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布宿接。 她就那樣靜靜地躺著,像睡著了一般辕录。 火紅的嫁衣襯著肌膚如雪睦霎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天走诞,我揣著相機與錄音副女,去河邊找鬼。 笑死蚣旱,一個胖子當著我的面吹牛碑幅,可吹牛的內容都是我干的。 我是一名探鬼主播塞绿,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼沟涨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了异吻?” 一聲冷哼從身側響起裹赴,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诀浪,沒想到半個月后棋返,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡雷猪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年懊昨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片春宣。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡酵颁,死狀恐怖嫉你,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情躏惋,我是刑警寧澤幽污,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站簿姨,受9級特大地震影響距误,放射性物質發(fā)生泄漏。R本人自食惡果不足惜扁位,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一准潭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧域仇,春花似錦刑然、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垦细。三九已至择镇,卻和暖如春括改,著一層夾襖步出監(jiān)牢的瞬間腻豌,已是汗流浹背嘱能。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工饲梭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人焰檩。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像析苫,于是被迫代替她去往敵國和親兜叨。 傳聞我的和親對象是個殘疾皇子衩侥,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容