Map
데이터는 프로그램 개발 중에 흔히 사용되는 작업입니다. RxJS
를 사용하여 코드에서 데이터 스트림을 생성할 때 필요한 형식에 관계없이 데이터를 매핑하는 방법이 필요할 가능성이 높습니다. RxJS
는 mergeMap
, switchMap
및 concatMap
뿐만 아니라 일반 map
함수도 제공합니다. 이러한 기능은 약간 다르게 처리됩니다. [추천 관련 튜토리얼: "Angular 튜토리얼"]Map
数据是程序开发时的一种常见操作。当在代码中使用RxJS
来生成数据流时,很可能最终需要一种方法来将数据映射成需要的任何格式。RxJS
提供了常规的 map
函数,还有 mergeMap
、switchMap
和concatMap
这样的函数,它们的处理方式略有不同。【相关教程推荐:《angular教程》】
map
操作符是最常见的。对于Observable
发出的每个值,都可以应用一个函数来修改数据。返回值将在后台被重新释放为Observable
,这样就可以在流中继续使用它。它的工作原理与在数组中使用它的方法非常相似。
不同之处在于,数组将始终只是数组,而在映射时,将获得数组中当前的索引值。对于observable
,数据的类型可以是各种类型。这意味着可能需要在 Observable map
函数中做一些额外的操作来获得想要的结果。看下面的例子::
import { of } from "rxjs"; import { map } from "rxjs/operators"; // 创建数据 const data = of([ { brand: "保时捷", model: "911" }, { brand: "保时捷", model: "macan" }, { brand: "法拉利", model: "458" }, { brand: "兰博基尼", model: "urus" } ]); // 按照brand model的格式输出,结果:["保时捷 911", "保时捷 macan", "法拉利 458", "兰博基尼 urus"] data.pipe(map(cars => cars.map(car => `${car.brand} ${car.model}`))).subscribe(cars => console.log(cars)); // 过滤数据,只保留brand为porsche的数据,结果:[{"brand":"保时捷","model":"911"},{"brand":"保时捷","model":"macan"}] data.pipe(map(cars => cars.filter(car => car.brand === "保时捷"))).subscribe(cars => console.log(cars));
首先用一系列汽车创建了可观察对象。然后订阅这个可观测值2次。
第一次修改数据时,得到了一个由brand
和model
字符串连接起来的数组。
第二次修改数据时,得到了一个只有brand
为保时捷
的数组。
在这两个例子中,使用Observable
map操作符来修改由Observable
发出的数据。返回修改的结果,然后map
操作符将结果封装到一个可观察对象中,以便后面可以subscribe
。
现在假设有这样一个场景,有一个可观察到的对象,它发出一个数组,对于数组中的每一项,都需要从服务器获取数据。
可以通过订阅数组来做到这一点,然后设置一个映射来调用一个处理API调用的函数,订阅其结果。如下:
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()
的结果作为“内部”可观察对象。从理论上讲,必须同时接受外部和内部的可观测数据。可以是这样的:
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
将“内部”可观察对象的值合并为“外部”可观察对象时,不再需要订阅两次。如下:
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
将是这个问题的最佳解决方案。下面是完整的例子:
import { of, from } from "rxjs"; import { map, mergeMap, delay, mergeAll } from "rxjs/operators"; const getData = param => { return of(`检索参数: ${param}`).pipe(delay(1000)); }; // 使用 map from([1, 2, 3, 4]) .pipe(map(param => getData(param))) .subscribe(val => val.subscribe(data => console.log(data))); // 使用 map 和 mergeAll from([1, 2, 3, 4]) .pipe( map(param => getData(param)), mergeAll() ) .subscribe(val => console.log(val)); // 使用 mergeMap from([1, 2, 3, 4]) .pipe(mergeMap(param => getData(param))) .subscribe(val => console.log(val));
SwitchMap
具有类似的行为,它也将订阅内部可观察对象。然而,switchMap
是switchAll
和map
的组合。SwitchAll
取消先前的订阅并订阅新订阅。在上面的场景中,想要为“外部”可观察对象数组中的每一项执行API调用,但switchMap
并不能很好地工作,因为它将取消前3个订阅,只处理最后一个订阅。这意味着只会得到一个结果。完整的例子可以在这里看到:
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)); }; // 使用 a regular map from([1, 2, 3, 4]) .pipe(map(param => getData(param))) .subscribe(val => val.subscribe(data => console.log(data))); // 使用 map and switchAll from([1, 2, 3, 4]) .pipe( map(param => getData(param)), switchAll() ) .subscribe(val => console.log(val)); // 使用 switchMap from([1, 2, 3, 4]) .pipe(switchMap(param => getData(param))) .subscribe(val => console.log(val));
虽然switchMap
不适用于当前的场景,但它适用于其他场景。例如,如果将筛选器列表组合到数据流中,并在更改筛选器时执行API调用,那么它将派上用场。如果先前的筛选器更改仍在处理中,而新的更改已经完成,那么它将取消先前的订阅,并在最新的更改上启动新的订阅。这里可以看到一个例子:
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); }); }; // 使用 switchMap activeFilters.pipe(switchMap(param => getData(param))).subscribe(val => console.log(val)); applyFilters();
正如在控制台中看到的,getData
只记录一次所有参数。节省了3次API的调用。
最后一个例子是concatMap
。concatMap
订阅了内部可观察对象。但与switchMap
不同的是,如果有一个新的观察对象进来,它将取消当前观察对象的订阅,concatMap
map
연산자가 가장 일반적입니다. Observable
이 내보낸 각 값에 대해 함수를 적용하여 데이터를 수정할 수 있습니다. 반환 값은 스트림에서 다시 사용할 수 있도록 배후에서 Observable
로 할당 해제됩니다. 이는 배열과 함께 사용하는 것과 매우 유사하게 작동합니다. 🎜🎜차이점은 배열은 항상 배열일 뿐인 반면, 매핑할 때는 배열의 현재 인덱스 값을 가져옵니다. observable
의 경우 데이터 유형은 다양한 유형일 수 있습니다. 즉, 원하는 결과를 얻으려면 관찰 가능한 지도
함수에서 몇 가지 추가 작업을 수행해야 할 수도 있습니다. 아래 예를 보세요: :🎜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)); }; // 使用map from([1, 2, 3, 4]) .pipe(map(param => getData(param))) .subscribe(val => val.subscribe(data => console.log("map:", data))); // 使用mergeMap from([1, 2, 3, 4]) .pipe(mergeMap(param => getData(param))) .subscribe(val => console.log("mergeMap:", val)); // 使用concatMap from([1, 2, 3, 4]) .pipe(concatMap(param => getData(param))) .subscribe(val => console.log("concatMap:", val));🎜 먼저 일련의 자동차로 관찰 가능 항목을 만듭니다. 그런 다음 이 Observable을 2번 구독하세요. 🎜
brand
와 model 연결된 배열. 🎜
브랜드
만 Porsche
인 배열을 얻었습니다. 🎜Observable
맵 연산자를 사용하여 Observable
에서 내보낸 데이터를 수정합니다. 수정된 결과가 반환되고 map
연산자는 나중에 구독
할 수 있도록 결과를 관찰 가능한 객체로 캡슐화합니다. 🎜map
함수는 getData
함수의 값을 반환합니다. 이 경우에는 관찰 가능합니다. 그러나 이는 문제를 야기합니다. 이제 처리해야 할 추가 관찰 항목이 있습니다. 🎜🎜이를 더 명확히 하려면: from([1,2,3,4])
를 "외부" 관찰 가능 항목으로, getData()
의 결과는 "내부" 관찰 가능 항목으로 " "관찰 가능한 개체. 이론적으로는 외부 관찰 가능 항목과 내부 관찰 가능 항목이 모두 허용되어야 합니다. 다음과 같이 보일 수 있습니다. 🎜rrreee🎜상상할 수 있듯이 이는 Subscribe
를 두 번 호출해야 하는 이상적인 상황과는 거리가 멀습니다. 여기가 mergeMap
이 작동하는 곳입니다. MergeMap
은 기본적으로 mergeAll
과 map
의 조합입니다. MergeAll
은 "내부" 관찰 가능 객체를 구독하는 일을 담당합니다. MergeAll
이 "내부" 관찰 가능 객체의 값을 "외부" 관찰 가능 객체에 병합하면, 두 개의 Second-rate를 구독할 필요가 없습니다. 다음과 같습니다: 🎜rrreee🎜이것이 훨씬 좋습니다. mergeMap
이 이 문제에 대한 최상의 솔루션이 될 것입니다. 전체 예는 다음과 같습니다. 🎜rrreeeSwitchMap
은 유사한 동작을 가지며 내부도 구독합니다. 관찰 가능. 그러나 switchMap
은 switchAll
과 map
의 조합입니다. SwitchAll
이전 구독을 취소하고 새 구독을 구독합니다. 위 시나리오에서 "외부" 관찰 가능 배열의 각 항목에 대해 API 호출을 수행하려고 하지만 switchMap
은 처음 3개 구독을 취소하고 마지막 구독만 취소하므로 잘 작동하지 않습니다. 구독이 처리되었습니다. 즉, 하나의 결과만 얻게 됩니다. 전체 예는 여기에서 볼 수 있습니다. 🎜rrreee🎜 switchMap
은 현재 시나리오에서는 작동하지 않지만 다른 시나리오에서는 작동합니다. 예를 들어 필터 목록을 데이터 흐름에 결합하고 필터가 변경될 때 API 호출을 수행하는 경우 유용합니다. 이전 필터 변경이 아직 처리 중이고 새 변경이 완료된 경우 이전 구독을 취소하고 최신 변경에 따라 새 구독을 시작합니다. 예는 다음에서 볼 수 있습니다. 🎜rrreee🎜콘솔에서 볼 수 있듯이 getData
는 모든 매개변수를 한 번만 기록합니다. 3개의 API 호출을 저장했습니다. 🎜concatMap
입니다. concatMap
은 내부 관찰 가능 항목을 구독합니다. 그러나 switchMap
과 달리 새로운 관찰 개체가 들어오면 현재 관찰 개체의 구독이 취소됩니다. concatMap
은 현재 관찰 개체가 완료될 때까지 구독하지 않습니다. 관찰 대상. 이것의 장점은 관찰 가능한 객체가 신호를 방출하는 순서가 유지된다는 것입니다. 이를 입증하려면: 🎜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)); }; // 使用map from([1, 2, 3, 4]) .pipe(map(param => getData(param))) .subscribe(val => val.subscribe(data => console.log("map:", data))); // 使用mergeMap from([1, 2, 3, 4]) .pipe(mergeMap(param => getData(param))) .subscribe(val => console.log("mergeMap:", val)); // 使用concatMap 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
。
更多编程相关知识,请访问:编程视频!!
위 내용은 RxJS가 Angular에서 데이터 작업을 매핑하는 방법에 대한 간략한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!