0

0

浅谈Angular中RxJS如何映射数据操作

青灯夜游

青灯夜游

发布时间:2021-07-06 11:56:09

|

1939人浏览过

|

来源于掘金社区

转载

浅谈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

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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

0

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.29

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

19

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

16

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

571

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

213

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

353

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

11

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue.js:纪录片
Vue.js:纪录片

共1课时 | 0.2万人学习

Angular js入门篇
Angular js入门篇

共17课时 | 3.5万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号