RxJS 的操作符理解起來確實比較複雜,比如最常用的幾種 map 操作符,本篇就來使勁衝一衝它們!!
- 原創文章,非商業轉載請説名出處
map 操作想必大家一定不陌生:
const { of } = Rx;
const { map } = RxOperators;
const namesObservable = of('A', 'B');
namesObservable.pipe(
map(name => `map ${name}`)
)
namesObservable .subscribe(result => console.log(`${result}`))
// map A
// map B
很直觀,因為 map 映射的是“值”,所以足夠簡單~
但是,如果説,map 映射的是 observable 呢 ?
const { of } = Rx;
const { map } = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return of(`${name} 1`,`${name} 2`);
}
namesObservable.pipe(
map(name => http(name))
)
namesObservable.subscribe(result => console.log(`${result}`))
// 則會得到兩個 observable 對象
// ****observable{ .. }
// observable{ .. }
我們在 [](https://rxviz.com/)https://rxviz.com/ 的彈珠圖中,可以清晰的看到:返回的仍是 observable
並且 observable 由最初的 1 個,變成了 2 個(圓圈就是 observable),數據仍在裏面沒有被訂閲解析出來。
雖然,我們可以用粗暴的方法,在訂閲 .subscribe 裏面再次調用訂閲 .subscribe ,則可得值:
const { of } = Rx;
const { map } = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return of(`${name} 1`,`${name} 2`);
}
namesObservable.pipe(
map(name => http(name))
)
namesObservable .subscribe(resultObservable => {
resultObservable.subscribe(result => console.log(`${result}`) )
})
// A1
// A2
// B1
// B2
但是,這樣包裹寫法註定是不優雅的,所以,為了解決這個差異,RxJS 引入了 —— Flattening(扁平化)策略!!
我們可以藉助 flatMap 操作符,則能得到同樣的解析值的效果~
flatMap 其實也就是我們熟知的 mergeMap 操作符;
代碼如下:
const { of } = Rx;
const { mergeMap} = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return of(`${name} 1`,`${name} 2`);
}
namesObservable.pipe(
mergeMap(name => http(name))
)
namesObservable.subscribe(result => console.log(`${result}`))
// A1
// A2
// B1
// B2
更進一步,沿着這種偏平化策略的思路,除了 mergeMap,RxJS 又引入了 switchMap、concatMap 和 exhaustMap,它們能夠提供不同方向的拉平策略。
我們再借助 [](https://rxviz.com/)https://rxviz.com/ 的彈珠圖,一眼便能看到它們的差異:
設置一個定時器,每一秒都發出一個 observable,一共發 3 次,來看下分別得值;
- mergeMap
const { of,interval} = Rx;
const { mergeMap,take,map } = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return interval(1000)
.pipe(
take(3),
map(()=>of(`${name} 1`,`${name} 2`))
)
}
namesObservable.pipe(
mergeMap(name => http(name))
)
mergeMap 會同時維護多個活動的內部訂閲;
- switchMap
const { of,interval} = Rx;
const { switchMap,take,map } = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return interval(1000)
.pipe(
take(3),
map(()=>of(`${name} 1`,`${name} 2`))
)
}
namesObservable.pipe(
switchMap(name => http(name))
)
switchMap,在每次發出時,會取消前一個內部 observable 的訂閲,然後訂閲一個新的 observable;
- concatMap
const { of,interval} = Rx;
const { concatMap ,take,map } = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return interval(1000)
.pipe(
take(3),
map(()=>of(`${name} 1`,`${name} 2`))
)
}
namesObservable.pipe(
concatMap (name => http(name))
)
concatMap 會在之前前一個內部 observable 完成後,才會訂閲下一個;
- exhaustMap
const { of,interval} = Rx;
const { exhaustMap ,take,map } = RxOperators;
const namesObservable = of('A', 'B');
const http =(name)=>{
return interval(1000)
.pipe(
take(3),
map(()=>of(`${name} 1`,`${name} 2`))
)
}
namesObservable.pipe(
exhaustMap (name => http(name))
)
exhaustMap 映射成內部 observable,忽略其他值直到該 observable 完成;
OK,以上便是本篇分享。
覺得不錯點個贊吧👍👍👍,您的鼓勵,我的動力,堅持輸出質量好文~~ 歡迎評論討論
我是掘金安東尼,輸出暴露輸入,技術洞見生活。再會吧~~ 👋👋👋