歡迎指導與討論:)
前言
本文是筆者翻譯 RxJS 5.X 官網各類operation操作系列的的第一篇 —— transform轉換。如有錯漏,希望大家指出提醒O(∩_∩)O。更詳細的資料盡在rxjs官網 【http://reactivex.io/rxjs/manual/overview.htm】與帶有demo例子的網站【http://xgrommx.github.io/rx-book/content/observable】。
本文有關於transform操作的內容:buffer、bufferCount、bufferTime、bufferToggle、bufferWhen、concatMap、concatMapTo、exhaustMap、expand、groupBy、map、mapTo、merge、mergeMap、mergeMapTo、mergerScan、mergeAll、pairwise、partition、pluck、scan、switchMap、switchMapTo、window、windowCount、windowTime、windowToggle、windowWhen、flatMap。
1. buffer —— 自定義分組
建立一個緩沖區(Observable),將數據源產生的值收集到緩沖區中,然后通過一些規則,讓這些值重新發射。
var source = Rx.Observable.timer(0, 50) .buffer(function () { return Rx.Observable.timer(125); }) .take(3); // [0, 1, 2], [3, 4, 5], [6, 7]
2. bufferCount —— 根據數據量分組
建立一個緩沖區(Observable),將數據源收集到緩沖區中,然后根據參數n對數據源進行分組,每組有n個數據,最后把分組好的數據集合發射出來
var source = Rx.Observable.range(1, 6) .bufferCount(2); // [ 1, 2 ], [ 3, 4 ], [ 5, 6]
3. bufferTime —— 根據時間分組
建立一個緩沖區(Observable),將數據源收集到緩沖區中,然后根據時間參數n對數據源進行分組,在同一n毫秒下的數據為一組,然后把分組好的數據集合發射出來。
var source = Rx.Observable.timer(0,1000); //序列:0 1 2 3 ...
var target = source.bufferTime(2500); //序列:[0,1,2] [3,4] ...
4. bufferToggle —— 根據自定義開始與結束分組
bufferToggle(open: Observable, () => close: Observalbe : Observalbe<T[]>)。(參考自資料)
const source$ = Rx.Observable.interval(500); const open$ = Rx.Observable.interval(1500); const close$ = Rx.Observable.interval(1000); const foo$ = source$.bufferToggle(open$, ( ) => { return close$; }); /** ---0---1---2---3---4---5---6---7---8---9----.... (source) -----------1-----------2-----------3--------... (open) --- ---x --- ---x --- ---x... (close) bufferToggle(open$, () => close$) ------------------([2,3])-----([5.6])-----([8,9])--... */
5. bufferWhen —— 根據自定義關閉函數進行分組
bufferWhen( closeFuc: function( ): Observable ): Observable<T[]>
每當關閉函數發射值時,為當前數據進行一次分組,並把這次分組后的數據組返回。
const open$ = Rx.Observable.interval(1000); const click$ = Rx.Observable.fromEvent(document, 'click'); var w = open$.bufferWhen(( ) => click$); w.subscribe(x => console.log(x)) // 每次點擊都能進行一次分組 // 第二秒點擊第一次:[0, 1, 2] // 第六秒點擊第二次:[3, 4, 5, 6]
6. concatMap —— 數據遍歷映射,並【依次】拼接
將數據源中的每項數據都執行一遍指定的函數,並且此函數需返回一個Observable,最后將各個運行函數后的Observable依次拼接起來。mergeMap是把運行后合並起來。
var source = Rx.Observable.of(1,2,3); var mf = function(item){ return Rx.Observable.range(item,3); }; var target = source.concatMap(mf); //序列:1 2 3, 2 3 4, 3 4 5
7. concatMapTo —— 數據遍歷映射為特定的Observable,並【依次】拼接
與concatMap類似,但是將每個值映射到的是相同內容Observable
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.concatMapTo(Rx.Observable.interval(1000).take(4)); result.subscribe(x => console.log(x)); // 每次點擊都映射為 interval(1000).take(4)
8. exhaustMap —— 在有空時才進行數據映射
將數據源中的每項數據都執行一遍指定的函數,並且此函數需返回一個Observable,此時立即執行當前的Observable的subscribe函數,在subscribe函數執行期間,若數據源有新的數據到達也不會執行所指定的函數並返回Observable。即只有當,當前Observable.subscribe執行完畢,才接受下一個數據,並重復上述過程。
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.exhaustMap((ev) =>Rx.Observable.interval(1000).take(4)); result.subscribe(x => console.log(x)); // 每次點擊,都會在4秒內,產生[0, 1, 2, 3] // 在產生期間,新的點擊不會再產生[0,1,2,3]
9. expand —— 遞歸地數據映射
expand會把上次產生的值傳給自己,從而遞歸。
var clicks = Rx.Observable.fromEvent(document, 'click'); var powersOfTwo = clicks .mapTo(1) .expand(x => Rx.Observable.of(2 * x).delay(1000)) .take(10); powersOfTwo.subscribe(x => console.log(x)); // 1, 2, 4, 8, 16, 32, 64, 128 ...
10. groupBy —— 根據指定條件對數據源進行分組
把數據源根據指定的條件函數進行分組,並得到Observable group。函數所返回的字符串,將作為每個分組(group)的key值。group可以被訂閱。
var source = Rx.Observable.timer(0,1000);//序列:0 1 2 ...
var gf = function(item){ return item %2 === 0 ? "EVEN":"ODD"; // 分為EVEN與ODD組
} var target = source.groupBy(gf); target.subscribe(x => { if ( x.key === 'EVEN' ) { // 根據key值選擇group
x.subscribe( x => console.log(x)) } });
11. map —— 對數據源每項進行特定轉換操作
var clicks = Rx.Observable.fromEvent(document, 'click'); var positions = clicks.map(ev => ev.clientX); positions.subscribe(x => console.log(x)); // 每次點擊輸出鼠標點擊的位置
12. mapTo —— 對數據源每項都轉換為指定的值/其他
var clicks = Rx.Observable.fromEvent(document, 'click'); var greetings = clicks.mapTo('Hi'); greetings.subscribe(x => console.log(x)) // 每次點擊都輸出'HI'
14. merge —— 對多個數據源進行合並
將多個Observable進行合並,每當其中一個Observable發射值時,都會被observer所收到。
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.merge(Rx.Observable.interval(1000)); result.subscribe(x => console.log(x)); // 不點擊的情況下,每秒輸出i, i為從零到n // 點擊一下,馬上輸出 $mouseEvent
14. mergeMap —— 對數據源每項進行特定轉換操作,然后合並
對數據源的所產生的所有值,經過函數轉換為Observable,然后合並所有的Observable到一個流中。concatMap則是對數據源的每項,經過函數轉換為Observable然后合並這些Observable到一個流中。
// mergeMap
var letters = Rx.Observable.of('a', 'b', 'c'); var result = letters.mergeMap(x => Rx.Observable.interval(1000).map(i => x+i) ); result.subscribe(x => console.log(x)); // 每秒輸出 'ai bi ci' i未從0到n
// concatMap
var letters = Rx.Observable.of('a', 'b', 'c'); var result = letters.concatMap(x => Rx.Observable.interval(1000).map(i => x+i).take(3) ); result.subscribe(x => console.log(x)); // 每秒依次輸出 a0, a1, a2, b0, b1, b2, c0, c1, c2
15. mergeMapTo—— 對數據源每項進行特定轉換操作,然后合並
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.mergeMapTo(Rx.Observable.interval(1000)); result.subscribe(x => console.log(x)); // 每次點擊都會產生一個新的observabl計時器,這個observabl會被合並到同一個流中
16. mergeScan —— 暫無
17. mergeAll —— 將高階Observable化為一階
mergeAll能將高階Obervable(能產生新Observable的Observable),全部扁平化(化為一階),並把這些Observable合並到一起,oberver能夠接收任意一個Observable所產生的值。它也能接收一個參數,表示當前時刻能merge的最大數量的Observable。與mergeMap/mergeMapTo的不同,mergeAll合成的是高階Obserbable,mergeMap/mergeMapTo是直接合並一階Observable。
// mergeAll無參數的情況
var clicks = Rx.Observable.fromEvent(document, 'click'); var higherOrder = clicks.map((ev) => Rx.Observable.interval(1000)); var firstOrder = higherOrder.mergeAll(); firstOrder.subscribe(x => console.log(x)); // 每次點擊都能產生一個新 Observable // mergeAll把這些Observable合並到同一個Observable上
// mergeAll有參數的情況
var clicks = Rx.Observable.fromEvent(document, 'click'); var higherOrder = clicks.map((ev) => Rx.Observable.interval(1000).take(5)); var firstOrder = higherOrder.mergeAll(2); firstOrder.subscribe(x => console.log(x)); // 每次點擊都能產生一個新 Observable // 但每個時刻只接收2個Observable,並把它們合並到一起 // 在隊列中等待的Observable會在當前Observable數量小於2時加入
18. pairwise —— 組合當前Observable的所發生每個值
pairwise把當前Observable所發生的每個值,組合為一個含有兩個值的數組,數組第一個值為當前項的值,數組第二個值為當下一項的值。
var a = Rx.Observable.interval(1000); var b = a.pairwise(); b.subscribe(x=>console.log(x)) // 依次輸出:[1, 2], [2, 3], [3, 4], [4, 5], ....
19. partition —— 把當前Observable分隔為兩組Observable
partition能根據指定條件對當前Observable分隔為兩組,符合情況的為一組,不符合情況的為一組,與groupBy類似。
var clicks = Rx.Observable.fromEvent(document, 'click'); var parts = clicks.partition(ev => ev.target.tagName === 'DIV'); var clicksOnDivs = parts[0]; // 組1
var clicksElsewhere = parts[1]; // 組2
clicksOnDivs.subscribe(x => console.log('DIV clicked: ', x)); clicksElsewhere.subscribe(x => console.log('Other clicked: ', x));
20. pluck —— 根據key值提取Observable所產生的值的value
pluck能根據key值,提取Observable所產生的值(需要為一個對象)的value,我們能夠傳入多個key值,則會深層地獲取value。
var clicks = Rx.Observable.fromEvent(document, 'click'); var tagNames = clicks.pluck('target', 'tagName'); tagNames.subscribe(x => console.log(x)); // 點擊哪里,就輸出哪的tagName --> 相當於輸出$event.target.tagName
21. scan —— 對Observable值的進行累積操作
對Observable所發射的值進行累積操作,如累加累乘等,性質與原生js的reduce類似。
var clicks = Rx.Observable.fromEvent(document, 'click'); var ones = clicks.mapTo(1); var seed = 0; var count = ones.scan((acc, one) => acc + one, seed); count.subscribe(x => console.log(x)); // 每次點擊輸出:1, 2,3, 4....
22. switchMap —— 對Observable進行轉換,並刷新當前Observable
switch接收一個函數,該函數會返回一個Observable,每當該函數又生成一個新的Observable時,新產生的Observable把上一個產生的Observable替換掉。即,有重新開始的意思。
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.switchMap((ev) => Rx.Observable.interval(1000)); result.subscribe(x => console.log(x)); // 每次點擊 會重新 從0到n開始輸出
23. switchMapTo —— 對Observable進行指定轉換,並刷新當前Observable
同上,只是switchMapTo直接接收一個指定的Observable作為參數,而swicthMap接收一個生成Observable的函數。
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.switchMapTo(Rx.Observable.interval(1000)); result.subscribe(x => console.log(x)); // 每次點擊會重新從0到n開始輸出
24. window —— 產生新的Observable
window能產生新的Observable。因此整個調用window的表達式,實際上是一個高階Observable(能產生Obervable的Observable, groupBy表達式也是高階)。高階Observable可以用mergeAll處理。
var clicks = Rx.Observable.fromEvent(document, 'click'); var interval = Rx.Observable.interval(1000); var result = clicks.window(interval) .map(win => win.take(2)) // each window has at most 2 emissions
.mergeAll(); // flatten the Observable-of-Observables
result.subscribe(x => console.log(x)); // 每次點擊 都往流中加入一個定時器
25. windowCount —— 根據 數量間隔 產生不同的Observable
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.windowCount(3) .map(win => win.skip(1)) // skip first of every 3 clicks
.mergeAll(); // flatten the Observable-of-Observables
result.subscribe(x => console.log(x));
26. windowTime —— 根據 時間間隔 產生不同的Observable
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks.windowTime(1000) .map(win => win.take(2)) // each window has at most 2 emissions
.mergeAll(); // flatten the Observable-of-Observables
result.subscribe(x => console.log(x));
27. windowWhen —— 根據參數產生不同的Observable
var clicks = Rx.Observable.fromEvent(document, 'click'); var result = clicks .windowWhen(() => Rx.Observable.interval(1000 + Math.random() * 4000)) .map(win => win.take(2)) // each window has at most 2 emissions
.mergeAll(); // flatten the Observable-of-Observables
result.subscribe(x => console.log(x));
28. flatMap —— 轉換的同時,進行高階到一階的扁平化
Rx.Observable.of( 1, 2, 3) .flatMap( x => Rx.Observable.range( x, 3 )) // 內部是另一個Observable .subscribe(x => console.log( x )); // 輸出 // 1 2 3, 2 3 4, 3 4 5