首頁  >  文章  >  web前端  >  淺談Angular中RxJS如何映射資料操作

淺談Angular中RxJS如何映射資料操作

青灯夜游
青灯夜游轉載
2021-07-06 11:56:091539瀏覽

淺談Angular中RxJS如何映射資料操作

Map 資料是程式開發時的常見操作。當程式碼中使用RxJS來產生資料流時,很可能最終需要一種方法來將資料對應成需要的任何格式。 RxJS提供了常規的map 函數,還有mergeMapswitchMapconcatMap這樣的函數,它們的處理方式略有不同。 【相關教學推薦:《angular教學》】

map

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次。

  • 第一次修改資料時,得到了一個由brandmodel字串連接起來的陣列。

  • 第二次修改資料時,得到了一個只有brand保時捷的陣列。

在這兩個範例中,使用Observable map運算子來修改由Observable所發出的資料。傳回修改的結果,然後map運算子將​​結果封裝到一個可觀察物件中,以便後面可以subscribe

MergeMap

現在假設有這樣一個場景,有一個可觀察到的對象,它發出一個數組,對於數組中的每一項,都需要從伺服器獲取數據。

可以透過訂閱陣列來做到這一點,然後設定一個映射來呼叫一個處理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本質上是mergeAllmap的組合。 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有類似的行為,它也會訂閱內部可觀察物件。然而,switchMapswitchAllmap的組合。 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

最後一個例子是concatMapconcatMap訂閱了內部可觀察物件。但與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毫秒之间。通过浏览器日志,可以看到mapmergeMap操作符将记录返回的任何值,而不遵循原始顺序。concatMap记录的值与它们开始时的值相同。

总结

将数据映射到所需的格式是一项常见的任务。RxJS附带了一些非常简洁的操作符,可以很好的完成这项工作。

概括一下:map用于将normal值映射为所需的任何格式。返回值将再次包装在一个可观察对象中,因此可以在数据流中继续使用它。当必须处理一个“内部”观察对象时,使用mergeMapswitchMapconcatMap更容易。如果只是想将数据转成Observable对象,使用mergeMap;如果需要丢弃旧的Observable对象,保留最新的Observable对象,使用switchMap;如果需要将数据转成Observable对象,并且需要保持顺序,则使用concatMap

更多编程相关知识,请访问:编程视频!!

以上是淺談Angular中RxJS如何映射資料操作的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除