RxJS流背后的一個關鍵設計原則是為您提供一個熟悉的遍歷機制,就像使用數(shù)組一樣窗骑。迭代器用于以與結構無關的方式遍歷數(shù)據(jù)容器殊鞭,或者獨立于用于利用這些元素的底層數(shù)據(jù)結構(無論是數(shù)組、樹闺魏、映射非洲,甚至是流)鸭限。此外,此模式還可以有效地將應用于每個元素的業(yè)務邏輯與迭代本身解耦两踏。旨在提供一個可以訪問每個元素并繼續(xù)訪問下一個元素的協(xié)議败京,如下圖所示:
現(xiàn)在將簡要地解釋一下這個模式,稍后將探討它是如何應用于stream
梦染。JavaScript ES6標準定義了迭代器協(xié)議赡麦,它允許您定義或定制任何可迭代對象的迭代行為。你最熟悉的可迭代對象是數(shù)組和字符串帕识。ES6又添加了Map和Set泛粹。使用RxJS,我們也把流視為可迭代的數(shù)據(jù)類型肮疗。
在ES6中晶姊,我們可以通過操作其底層迭代器來使任何對象可迭代∥被酰考慮一個迭代器對象们衙,它可以遍歷一個數(shù)字數(shù)組并緩沖一組連續(xù)元素。 在這里碱呼,業(yè)務執(zhí)行的邏輯是緩沖本身蒙挑,這對于將元素組合在一起非常有用形成任何尺寸的數(shù)值集,如下圖所示愚臀。
下面代碼簡單實現(xiàn)了這個自定義迭代器忆蚀,包括緩沖的邏輯。
function BufferIterator(arr, bufferSize = 2) {
// 重寫數(shù)組的iterator機制
this[Symbol.iterator] = function() {
let nextIndex = 0;
return {
next: () => {
if(nextIndex >= arr.length) {
return {done: true};
} else {
let buffer = new Array(bufferSize);
for (let i=0; i < bufferSize; i++) {
buffer[i] = arr([nextIndex++]);
}
return { value: buffer, done: false};
}
}
}
}
}
此API的任何客戶端只需要與next()函數(shù)進行交互,而不需要關心后面的業(yè)務邏輯,使用for...of時就會觸發(fā)迭代器機制.
清單2.2中的next()函數(shù)用于自定義迭代的行為姑裂,用于for...of或任何其他循環(huán)機制馋袜。 在RxJS中,
觀察者也實現(xiàn)了類似的接口炭分,以便持續(xù)向流發(fā)送信號事件桃焕。
注意:
由于迭代器協(xié)議是ES6發(fā)布的剑肯,而Rxjs是在此之前開發(fā)的捧毛,所以它并沒有使用迭代器開發(fā)。如果想對迭代器做更多的了解,請查看
迭代器可以使用我們輕松的利用JavaScript的運行機制來定義自己的迭代。接下來給大家展示如何使用BufferIterator:
const arr = [1, 2, 3, 4, 5, 6]
for(let i of new BufferIterator(arr, 2)) {
console.log(i)
}
//-> [1, 2] [3, 4] [5, 6]
for(let i of new BufferIterator(arr, 3)) {
console.log(i)
}
//-> [1, 2, 3] [4, 5, 6]
也許你已經(jīng)注意到呀忧,迭代機制和緩沖邏輯是完全分離的师痕。當我們訂閱流時,完全可以以相同的方式遍歷許多其他數(shù)據(jù)源而账,比如鼠標和鍵盤胰坟。理論上來說,假如Stream
對象是一個可迭代對象泞辐,那我們只需要一個循環(huán)就可以得到所有的事件:
const stream = Stream(R, x, J, S)[Symbol.iterator]();
for(let keyEvent of stream) {
console.log(event.keyCode);
}
//-> 82, 120, 74, 83
Rxjs中的Stream
也是遵守Iterator
機制的笔横,流的訂閱者會監(jiān)聽其中所有的事件。正如前面所說的咐吼,迭代器成功的幫我們實現(xiàn)了將迭代和迭代數(shù)據(jù)以及業(yè)務邏輯的解耦吹缔。