本文摘自PHP中文网,作者青灯夜游,侵删。

Map
数据是程序开发时的一种常见操作。当在代码中使用RxJS
来生成数据流时,很可能最终需要一种方法来将数据映射成需要的任何格式。RxJS
提供了常规的 map
函数,还有 mergeMap
、switchMap
和concatMap
这样的函数,它们的处理方式略有不同。【相关教程推荐:《angular教程》】
map
map
操作符是最常见的。对于Observable
发出的每个值,都可以应用一个函数来修改数据。返回值将在后台被重新释放为Observable
,这样就可以在流中继续使用它。它的工作原理与在数组中使用它的方法非常相似。
不同之处在于,数组将始终只是数组,而在映射时,将获得数组中当前的索引值。对于observable
,数据的类型可以是各种类型。这意味着可能需要在 Observable map
函数中做一些额外的操作来获得想要的结果。看下面的例子::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import { of } from "rxjs" ;
import { map } from "rxjs/operators" ;
const data = of([
{
brand: "保时捷" ,
model: "911"
},
{
brand: "保时捷" ,
model: "macan"
},
{
brand: "法拉利" ,
model: "458"
},
{
brand: "兰博基尼" ,
model: "urus"
}
]);
data.pipe(map(cars => cars.map(car => `${car.brand} ${car.model}`))).subscribe(cars => console.log(cars));
data.pipe(map(cars => cars.filter(car => car.brand === "保时捷" ))).subscribe(cars => console.log(cars));
|
首先用一系列汽车创建了可观察对象。然后订阅这个可观测值2次。
在这两个例子中,使用Observable
map操作符来修改由Observable
发出的数据。返回修改的结果,然后map
操作符将结果封装到一个可观察对象中,以便后面可以subscribe
。
MergeMap
现在假设有这样一个场景,有一个可观察到的对象,它发出一个数组,对于数组中的每一项,都需要从服务器获取数据。
可以通过订阅数组来做到这一点,然后设置一个映射来调用一个处理API调用的函数,订阅其结果。如下:
1 2 3 4 5 6 7 8 9 10 | import { of, from } from "rxjs" ;
import { map, delay } from "rxjs/operators" ;
const getData = param => {
return of(`检索参数: ${param}`).pipe(delay(1000));
};
from([1, 2, 3, 4])
.pipe(map(param => getData(param)))
.subscribe(val => console.log(val));
|
map
函数返回getData
函数的值。在这种情况下,这是可观测的。但这产生了一个问题:因为现在要处理一个额外的可观测值。
为了进一步阐明这一点:from([1,2,3,4])
作为“外部”可观察对象,getData()
的结果作为“内部”可观察对象。从理论上讲,必须同时接受外部和内部的可观测数据。可以是这样的:
1 2 3 4 5 6 7 8 9 10 | import { of, from } from "rxjs" ;
import { map, delay } from "rxjs/operators" ;
const getData = param => {
return of(`检索参数: ${param}`).pipe(delay(1000));
};
from([1, 2, 3, 4])
.pipe(map(param => getData(param)))
.subscribe(val => val.subscribe(data => console.log(data)));
|
可以想象,这与必须调用Subscribe
两次的理想情况相去甚远。这就是mergeMap
发挥作用的地方。MergeMap
本质上是mergeAll
和map
的组合。MergeAll
负责订阅“内部”可观察对象,当MergeAll
将“内部”可观察对象的值合并为“外部”可观察对象时,不再需要订阅两次。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { of, from } from "rxjs" ;
import { map, delay, mergeAll } from "rxjs/operators" ;
const getData = param => {
return of(`检索参数: ${param}`).pipe(delay(1000));
};
from([1, 2, 3, 4])
.pipe(
map(param => getData(param)),
mergeAll()
)
.subscribe(val => console.log(val));
|
这已经好多了,mergeMap
将是这个问题的最佳解决方案。下面是完整的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import { of, from } from "rxjs" ;
import { map, mergeMap, delay, mergeAll } from "rxjs/operators" ;
const getData = param => {
return of(`检索参数: ${param}`).pipe(delay(1000));
};
from([1, 2, 3, 4])
.pipe(map(param => getData(param)))
.subscribe(val => val.subscribe(data => console.log(data)));
from([1, 2, 3, 4])
.pipe(
map(param => getData(param)),
mergeAll()
)
.subscribe(val => console.log(val));
from([1, 2, 3, 4])
.pipe(mergeMap(param => getData(param)))
.subscribe(val => console.log(val));
|
SwitchMap
SwitchMap
具有类似的行为,它也将订阅内部可观察对象。然而,switchMap
是switchAll
和map
的组合。SwitchAll
取消先前的订阅并订阅新订阅。在上面的场景中,想要为“外部”可观察对象数组中的每一项执行API调用,但switchMap
并不能很好地工作,因为它将取消前3个订阅,只处理最后一个订阅。这意味着只会得到一个结果。完整的例子可以在这里看到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import { of, from } from "rxjs" ;
import { map, delay, switchAll, switchMap } from "rxjs/operators" ;
const getData = param => {
return of(`retrieved new data with param ${param}`).pipe(delay(1000));
};
from([1, 2, 3, 4])
.pipe(map(param => getData(param)))
.subscribe(val => val.subscribe(data => console.log(data)));
from([1, 2, 3, 4])
.pipe(
map(param => getData(param)),
switchAll()
)
.subscribe(val => console.log(val));
from([1, 2, 3, 4])
.pipe(switchMap(param => getData(param)))
.subscribe(val => console.log(val));
|
虽然switchMap
不适用于当前的场景,但它适用于其他场景。例如,如果将筛选器列表组合到数据流中,并在更改筛选器时执行API调用,那么它将派上用场。如果先前的筛选器更改仍在处理中,而新的更改已经完成,那么它将取消先前的订阅,并在最新的更改上启动新的订阅。这里可以看到一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import { of, from, BehaviorSubject } from "rxjs" ;
import { map, delay, switchAll, switchMap } from "rxjs/operators" ;
const filters = [ "brand=porsche" , "model=911" , "horsepower=389" , "color=red" ];
const activeFilters = new BehaviorSubject( "" );
const getData = params => {
return of(`接收参数: ${params}`).pipe(delay(1000));
};
const applyFilters = () => {
filters.forEach((filter, index) => {
let newFilters = activeFilters.value;
if (index === 0) {
newFilters = `?${filter}`;
} else {
newFilters = `${newFilters}&${filter}`;
}
activeFilters.next(newFilters);
});
};
activeFilters.pipe(switchMap(param => getData(param))).subscribe(val => console.log(val));
applyFilters();
|
正如在控制台中看到的,getData
只记录一次所有参数。节省了3次API的调用。
ConcatMap
最后一个例子是concatMap
。concatMap
订阅了内部可观察对象。但与switchMap
不同的是,如果有一个新的观察对象进来,它将取消当前观察对象的订阅,concatMap
在当前观察对象完成之前不会订阅下一个观察对象。这样做的好处是保持了可观测对象发出信号的顺序。为了演示这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import { of, from } from "rxjs" ;
import { map, delay, mergeMap, concatMap } from "rxjs/operators" ;
const getData = param => {
const delayTime = Math.floor(Math.random() * 10000) + 1;
return of(`接收参数: ${param} and delay: ${delayTime}`).pipe(delay(delayTime));
};
from([1, 2, 3, 4])
.pipe(map(param => getData(param)))
.subscribe(val => val.subscribe(data => console.log( "map:" , data)));
from([1, 2, 3, 4])
.pipe(mergeMap(param => getData(param)))
.subscribe(val => console.log( "mergeMap:" , val));
from([1, 2, 3, 4])
.pipe(concatMap(param => getData(param)))
.subscribe(val => console.log( "concatMap:" , val));
|
getData
函数的随机延迟在1到10000毫秒之间。通过浏览器日志,可以看到map
和mergeMap
操作符将记录返回的任何值,而不遵循原始顺序。concatMap
记录的值与它们开始时的值相同。
总结
将数据映射到所需的格式是一项常见的任务。RxJS
附带了一些非常简洁的操作符,可以很好的完成这项工作。
概括一下:map
用于将normal
值映射为所需的任何格式。返回值将再次包装在一个可观察对象中,因此可以在数据流中继续使用它。当必须处理一个“内部”观察对象时,使用mergeMap
、switchMap
或concatMap
更容易。如果只是想将数据转成Observable
对象,使用mergeMap
;如果需要丢弃旧的Observable
对象,保留最新的Observable
对象,使用switchMap
;如果需要将数据转成Observable
对象,并且需要保持顺序,则使用concatMap
。
更多编程相关知识,请访问:编程视频!!
以上就是浅谈Angular中RxJS如何映射数据操作的详细内容,更多文章请关注木庄网络博客!
相关阅读 >>
Angular material的使用详解
浅谈Angular中http请求模块的用法
浅谈Angular中插槽的用法
详解Angular中的依赖注入模式
一文快速了解Angular中的ngrx/store框架
浅谈Angular中父子组件相互传参的方法
聊聊Angular中的指令(directive)
详解Angular中的material安装与使用
深入了解Angular中的表单
如何搭建测试环境?Angular测试工具集介绍
更多相关阅读请进入《Angular》频道 >>
人民邮电出版社
本书对 Vue.js 3 技术细节的分析非常可靠,对于需要深入理解 Vue.js 3 的用户会有很大的帮助。——尤雨溪,Vue.js作者
转载请注明出处:木庄网络博客 » 浅谈Angular中RxJS如何映射数据操作