之前的文章中我們介紹過(guò)了 scan 操作符钧嘶,和 JavaScript 數(shù)組的 reduce 函數(shù)很像棠众。其實(shí)在 RxJS 中也有 reduce 操作符∮芯觯可是既然已經(jīng)有了 scan 闸拿,為什么還會(huì)有 reduce?當(dāng)然是有差別的书幕,reduce 操作符必須要等到上游事件流發(fā)生 complete 事件后才會(huì)輸出新荤。比如下面的程序是永遠(yuǎn)看不到輸出的:
combineLatest(
timer$,
input$,
(timeValue, inputValue) => ({ count: timeValue, input: inputValue })
)
.pipe(
reduce((acc, curr) => acc + 1, 0),
tap(console.log)
)
因?yàn)樯嫌问录鞑粫?huì)產(chǎn)生 complete 事件。再來(lái)看看下面的代碼:
combineLatest(
timer$,
input$,
(timeValue, inputValue) => ({ count: timeValue, input: inputValue })
)
.pipe(
takeWhile(data => data.count < 3),
reduce((acc, curr) => acc + 1, 0),
tap(console.log)
)
這段程序會(huì)輸出嗎台汇?當(dāng)然苛骨,因?yàn)?taikeWhile 操作符的關(guān)系篱瞎,當(dāng)上游的事件對(duì)象的 count 屬性變成 3 時(shí),就會(huì)產(chǎn)生 complete 事件痒芝,reduce 操作就會(huì)把累積的數(shù)字輸出俐筋。因此當(dāng)我們需要知道累積函數(shù)每一步的值時(shí)就用 scan 操作符,如果只對(duì)最終結(jié)果感興趣就用 reduce 操作符严衬,但事件流一定是可以正常結(jié)束的才可以澄者。
下面我們來(lái)看看另一對(duì)有同樣行為又有微妙不同的操作符。combineLatest 和 withLatestFrom 操作符瞳步。讓我們精簡(jiǎn)下代碼闷哆,這樣更能看清它們的區(qū)別腰奋,首先看下 combineLatest 操作符:
const combineTimerAndInput$ = combineLatest(
timer$,
input$,
(timeValue, inputValue) => ({ count: timeValue, input: inputValue })
)
const subscription = combineTimerAndInput$
.subscribe(
x => console.log(x),
err => console.log(err),
() => console.log("complete")
);
之前的文章已經(jīng)提到单起,combineLatest 操作符一定要等到被 combine 的所有流都產(chǎn)生事件才會(huì)輸出,我們這里是兩個(gè)流劣坊。我們這樣操作看下效果:
- 點(diǎn)擊開(kāi)始按鈕嘀倒;
- 等幾秒,在文本框輸入內(nèi)容局冰;
- 等幾秒测蘑,點(diǎn)擊暫停按鈕;
- 在文本框輸入內(nèi)容康二;
動(dòng)圖如下:
總結(jié)一下現(xiàn)象:一開(kāi)始只有定時(shí)器產(chǎn)生事件碳胳,因此沒(méi)有輸出,當(dāng)在文本框開(kāi)始輸入內(nèi)容時(shí)沫勿,文本流產(chǎn)生了事件挨约。這樣兩個(gè)流都產(chǎn)生了事件,必然開(kāi)始有輸出产雹。但當(dāng)我們停止在文本框輸入時(shí)诫惭,文本流就沒(méi)有事件產(chǎn)生了,定時(shí)器還在不斷產(chǎn)生事件蔓挖,按理說(shuō)應(yīng)該停止輸出了夕土,但 combineLatest 依然輸出。同樣的瘟判,當(dāng)我們點(diǎn)擊了暫停按鈕怨绣,定時(shí)器流就沒(méi)有事件產(chǎn)生了,文本流這是也沒(méi)有事件產(chǎn)生拷获,因此是沒(méi)有輸出的梨熙,但當(dāng)我們保持暫停,在文本框輸入內(nèi)容時(shí)刀诬,combineLatest 又會(huì)開(kāi)始輸出咽扇。這就是 combineLatest 的工作機(jī)制邪财。只要被組合的流中都有過(guò)值,那么只要被組合的流中有一個(gè)產(chǎn)生新事件质欲,其他流都以最后一次產(chǎn)生的事件作為新事件共同輸出树埠。接下來(lái)看看 withLatestFrom 操作符,大家都會(huì)對(duì)這段解釋有更清晰的認(rèn)識(shí)嘶伟。
代碼如下:
const subscription = timer$
.pipe(
withLatestFrom(input$, (timeValue, inputValue) => ({
count: timeValue,
input: inputValue
})),
)
.subscribe(
x => console.log(x),
err => console.log(err),
() => console.log("complete")
);
首先怎憋,withLatestFrom 操作符是個(gè)對(duì)象方法,不像 combineLatest 是個(gè)靜態(tài)方法(combineLatest 在之前 RxJS 版本中也是對(duì)象方法)九昧。其次我們看到 withLatestFrom 的用法和 combineLatest 是一致的绊袋。測(cè)試步驟如下:
- 點(diǎn)擊開(kāi)始按鈕;
- 等幾秒铸鹰,在文本框輸入內(nèi)容癌别;
- 等幾秒,點(diǎn)擊暫停按鈕蹋笼;
- 在文本框輸入內(nèi)容展姐;
- 再次點(diǎn)擊開(kāi)始按鈕;
動(dòng)圖如下:
前面三步的效果和 combineLatest 是一樣的剖毯,到了第四步在文本框輸入內(nèi)容時(shí)圾笨,沒(méi)有了輸出;第五步又開(kāi)始有了輸出逊谋±薮铮總結(jié)一下:其實(shí)從 withLatestFrom 是對(duì)象函數(shù)就能看出,它是需要有事件流作為基礎(chǔ)的胶滋,combineLatest 則不然板鬓,是用來(lái)創(chuàng)造事件流的。也就是說(shuō)镀钓,當(dāng)上游事件流中沒(méi)有事件產(chǎn)生時(shí)穗熬,withLatestFrom 是不會(huì)有輸出的。符如其名丁溅,withLatestFrom 會(huì)把上游事件流中的事件和接收參數(shù)中的事件流的最后一個(gè)值一起進(jìn)行處理后輸出唤蔗。
如有任何問(wèn)題,請(qǐng)關(guān)注微信公眾號(hào)“讀一讀我”窟赏。