ホームページ  >  記事  >  ウェブフロントエンド  >  RxJS が Angular でデータ操作をどのようにマッピングするかについての簡単な説明

RxJS が Angular でデータ操作をどのようにマッピングするかについての簡単な説明

青灯夜游
青灯夜游転載
2021-07-06 11:56:091534ブラウズ

RxJS が Angular でデータ操作をどのようにマッピングするかについての簡単な説明

#マップ データはプログラム開発中の一般的な操作です。 RxJS を使用してコード内でデータ ストリームを生成する場合、最終的にはデータを必要な形式にマップする方法が必要になる可能性が高くなります。 RxJS は、通常の map 関数に加えて、mergeMapswitchMap、および concatMap 関数を提供します。 。 [関連チュートリアルの推奨事項: "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));

まず、一連の車を含むオブザーバブルを作成します。次に、この Observable を 2 回サブスクライブします。

  • 初めてデータを変更したとき、brandmodel という文字列で接続された配列が得られました。

  • データを 2 回目に変更したとき、brandPorsche だけを含む配列を取得しました。

両方の例で、Observable マップ演算子を使用して、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 を 2 回呼び出す必要があるという理想的な状況からは程遠いです。ここで mergeMap が活躍します。 MergeMap は本質的に mergeAllmap の組み合わせです。 MergeAll は、「内部」の監視可能なオブジェクトをサブスクライブする役割を果たします。 MergeAll が「内部」の監視可能なオブジェクトの値を「外部」の監視可能なオブジェクトにマージするとき、 2回購読する必要があります。次のように:

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 つのサブスクリプションをキャンセルし、最後のサブスクリプションのみを処理するため、あまりうまく機能しません。サブスクリプション。つまり、得られる結果は 1 つだけです。完全な例はここで見ることができます:

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 はすべてのパラメータを 1 回だけログに記録します。 3 つの API 呼び出しを保存しました。

ConcatMap

最後の例は 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毫秒之间。通过浏览器日志,可以看到mapmergeMap操作符将记录返回的任何值,而不遵循原始顺序。concatMap记录的值与它们开始时的值相同。

总结

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

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

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

以上がRxJS が Angular でデータ操作をどのようにマッピングするかについての簡単な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。