资讯专栏INFORMATION COLUMN

从命令式到响应式(五)

CoderBear / 2035人阅读

摘要:输出流只有在所有的输入流都完成以后才能完成,任何一条输入流上的错误都将立即推送到输出流上。如果没有转入输入流,输出流将会立即发出结束通知。返回值以数组形式获取到的每一个输入流的值,或者来自映射函数的值。返回值仅从最新的内部流上取值的流。

接着上一节的操作符继续,让我们直奔主题。

组合类操作符

组合类的操作符可以将不同流数据按一定的规则进行合并,从而获得所需要的完整数据。

combineLatest

实例方法

将多个输入流组合成一个输出流,输出流上的数据是由每一条输入流上的最后一条数据组合成的数据。

无论什么时间只要输入流上发出了数据,它就会把所有输入流上的最新数据组合成一条新的数据推送到输出流上。关键点在于任意一条被组合的流发出数据,输出流上都将有新的数据产生。

</>复制代码

  1. -a------b----c-----d------e---|
  2. --1--2-----3--4-----5---6---|
  3. combineLatest
  4. --a1-a2-b2--b3-c3-c4----d4-d5---e5-e6-|

另外它可以接受一个映射函数作为最后一个参数,所有输入流的值会依次传入映射函数作为它的参数。

返回 Observable 一条包含所有输入流最新值的流,或者是所有最新值的映射值的流。

示例

</>复制代码

  1. const weight = of(70,72,76,79,75);
  2. const height = of(1.76,1.77,1.78);
  3. const bmi = weight.combineLatest(height, (w, h) => w/h*h);
  4. bmi.subscribe(x => console.log("BMI is " + x);

withLatestFrom

实例方法

将多个输入流组合成一个输出流,输出流上的数据是由每一条输入流上的最后一条数据组合成的,但是组合动作只在源 Observable 发出值时发生,这里的源 Observable 指的是调用withLatestFrom的实例。也就是说只有当源 Observable 产生值时,才会产生新的值。

</>复制代码

  1. -a-----b--------------c------------d--e---|-->
  2. ----1-----2-----3--4--------5----|---->
  3. withLatestFrom
  4. ------b1------------c4-----------d5--e5---|-->

返回值 Observable 一条包含所有输入流最新值的流,或者是所有最新值的映射值的流。

和combineLatest一样它也可以接受映射函数作为参数。

示例

</>复制代码

  1. const clicks = fromEvent(document, "click");
  2. const timer = interval(1000);
  3. const result = clicks.withLatestFrom(timer)
  4. result.subscribe(x => console.log(x));

zip

实例方法

如果所有的输入都是流,那么将所有输入流对应位置上的值组合成一个新值,将这个新值作为输出流上的值。此外zip操作符还可以直接使用可转化为流的数据作为参数,比如数组,promise,字符串等。

</>复制代码

  1. --a------b------c------d---2--|->
  2. -----e------f------g-----h--|->
  3. zip
  4. ----ae------fb-----gc----hd-|->

返回值 Observable 将各输入流上对应的值组合成新的值发送给输出流或者先经过映射函数处理后再发送给输出流。

它也可以接受映射函数作为参数。

示例

</>复制代码

  1. const obs1 = from([1,2,3,4]);
  2. const obs2 = from(["a","b","c"]);
  3. obs1.zip(obs2)
  4. .subscribe(v => console.log(v));

</>复制代码

  1. const obs = interval(1000);
  2. const promise = new Promise(resolve => {
  3. setTimeout(() => resolve("hello"), 2000);
  4. });
  5. obs.zip(promise, (obs, promise) => promise + obs)
  6. .subscribe(v => console.log(v));

merge

实例方法

创建一条可以同时把所有输入流的值推送出去的流。它把多条输入流合并成一条输入流,所有输入流的值都可以在这条输出流上得到。

</>复制代码

  1. -a----------b----------c---|----->
  2. ------d---------e----------e----|-->
  3. merge
  4. -a----d----b----e-----c----e----|-->

合并所有输入流的订阅,不管是源 Observable 还是作为参数输入的 Observable,只是把值依次推送到输出流上,不作任何额外的更改。输出流只有在所有的输入流都完成以后才能完成,任何一条输入流上的错误都将立即推送到输出流上。

返回值 Observable 可以发送所有输入流上的值的Observable。

示例

</>复制代码

  1. const clicks = fromEvent(document, "click");
  2. const timer = interval(1000);
  3. const clicksOrTimer = clicks.merge(timer);
  4. clicksOrTimer.subscribe(x => console.log(x));

forkJoin

静态方法

将输入流的最后一个值合并后传给输出流。它的效果等同于Promise.all(),因此在你需要多个并发请求都返回结果时可以使用它。

forkJoin可以以参数或数组的形式接收任意数量的输入流。如果没有转入输入流,输出流将会立即发出结束通知。

它会等所有的输入流发出结束通知,然后发出一个包含所有输入流发出的最终值组成的数组,因此,传入n条输入流,得到的数组中将包含n个元素,每一个元素都是从对应顺序的输入流上取到的最后一个值。这也就意味着输出流只会发出一个值,紧接着就会发出结束通知。

为了使用输出流上获取到的数组的长度与输入流的数量保持一致,如果某一个输入流在发出结束通知之前没有发出过任何有效值,那么输出流也将会立刻结束并且不再发出任何值,尽管其它的输入流上可能会发出有效值。反过来,假如有一条输入流一直没有发出结束通知,输出流也不会发出值,除非另外一条输入像之前描述的那样只发了结束通知。总的来说就是为了让输出流发出值,所有的输入流都必须发出结束通知而且在此之前必须至少发出一个有效值。

如果输入流中的某一条发出了错误通知,输出流将会立即发出这个错误通知,并且立即取消对其它流的订阅。

</>复制代码

  1. ----2---3------4----5--|-->
  2. ----a----b------------d---|-->
  3. forkJoin
  4. --------------------------5d|

返回值 Observable 以数组形式获取到的每一个输入流的值,或者来自映射函数的值。

可以接收映射函数作为参数。

示例

</>复制代码

  1. const observable = forkJoin(
  2. of(1, 2, 3, 4),
  3. of(5, 6, 7, 8)
  4. );
  5. observable.subscribe(
  6. value => console.log(value),
  7. err => {},
  8. () => console.log("This is how it ends!")
  9. );

</>复制代码

  1. const observable = forkJoin(
  2. interval(1000).take(3),
  3. interval(500).take(4)
  4. );
  5. observable.subscribe(
  6. value => console.log(value),
  7. err => {},
  8. () => console.log("This is how it ends!")
  9. );
转换类型操作符

这里我们主要介绍那些可以处理高阶流的操作符。

map

实例方法

输出流上的值是使用一个映射函数将输入流上的值映射后得到新的值。

</>复制代码

  1. --------1-----------2----------3----------|--->
  2. map(v => v * 10);
  3. --------10----------20---------30---------|---->

返回值 Observable 发出映射后的值的流。

示例

</>复制代码

  1. fromEvent(document, "click")
  2. .map(event => event.clientX)
  3. .subscribe(v => console.log(v));

mergeMap

实例方法

将所有输入流的值都合并到一条流上。

</>复制代码

  1. -1-----2-----3---------|-->
  2. ---2----2----2--|-----> //第一次时的内部流,第2,3次的一样,这个流是直正的输入流
  3. mergeMap(v => Observable.of(v + 1).repeat(3));
  4. -2--2--2--3--3--3--4--4--4----|-->

输出流会把所有从映射函数中返回的内部流打平到一条流上。映射函数可以使用输入流的值来生成内部流。

返回值 Observable 一条合并了所有映射函数生成的内部流的流,内部流上的值都会在这条流上发出。

示例

</>复制代码

  1. of("a","b","c")
  2. .mergeMap(v => Rx.Observable.interval(1000).map(x => x + v ))
  3. .subscribe(v => console.log(v));

</>复制代码

  1. const source = of("Hello");
  2. const createPromise = v => new Promise(resolve => resolve(`I got ${v} from promise`));
  3. source.mergeMap(
  4. v => createPromise(v),
  5. (outValue, innerValue) => `Source: ${outValue},${innerValue}`
  6. )
  7. .subscribe(v => console.log(v));

switchMap

实例方法

在输入流发出值时,把它映射成一条内部流,然后把这条内部流打平成到输出流上,输出流上只会发出最近的内部流上的值。

</>复制代码

  1. -1---------3-----5----|->
  2. -10---10---10-| // 内部流
  3. switchMap(v => Observable.from([10,10,10]).map(x => x * v))
  4. -10---10---10-30---30-50---50---50-|

输出流上的值是由映射函数在输入流的值的基本上生成的内部流所发出的,输出流只允许观察一条内部流,当有新的内部流到达时,输出流将会取消对之前的内部流的订阅,转而订阅这个最新的内部流,并发出它上面的值。

返回值 Observable 仅从最新的内部流上取值的流。

示例

</>复制代码

  1. fromEvent(document, "click")
  2. .switchMap(event => interval(1000))
  3. .subscribe(v => console.log(v));

concatMap

实例方法

将多个流合并到一条流上,需要等待当前的流完成后才能开始合并下一个,合并过程按传入的顺序进行。

</>复制代码

  1. --1------------3---------5-----------|-->
  2. --10---10---10--|-->
  3. concatMap(i => 10*i----10*i---10*i)
  4. --10---10---10-30---30---30-50---50---50--|->

返回值 Observable 把输入的值经过映射成流后再连接起来的流。

示例

</>复制代码

  1. fromEvent(document, "click")
  2. .concatMap(event => Rx.Observable.interval(1000).take(3))
  3. .subscribe(v => console.log(v));

groupBy

实例方法

将输入流上的值按一定的规则分组成不同的流,然后把这些流发送给输出流,每一条流上都是一组符合相同条件的值。

</>复制代码

  1. ----1----2----3----4----5----|->
  2. groupBy(v => v%2);
  3. -----------------------------|->
  4. 2---------4---------|
  5. 1------3----------5----|

返回值 Observable 发出分组后的流的高阶流,分组的流都有一个唯一的key,并且该流中的值都是输入流上符合某一条件的值。

示例

</>复制代码

  1. of(
  2. {id: 1, name: "aze1"},
  3. {id: 2, name: "sf2"},
  4. {id: 2, name: "dg2"},
  5. {id: 1, name: "erg1"},
  6. {id: 1, name: "df1"},
  7. {id: 2, name: "sf2"},
  8. {id: 3, name: "qfs3"},
  9. {id: 2, name: "qsg"}
  10. )
  11. .groupBy(v => v.id)
  12. .mergeMap(group => group.reduce((acc,cur) => [...acc, cur],[]))
  13. .subscribe(v => console.log(v))
聚合类操作符

reduce

实例方法

在源 Observable 上应用一个累积函数,当源 Observable 结束时把累积的值推送给输出流,可以接受一个初始的累积值。

</>复制代码

  1. --------1-------2-------3---|-->
  2. reduce((acc,cur) => acc + cur, 0);
  3. ----------------------------4|

这个操作符的行为与数组的reduce方法相同。使用一个累积函数来处理流上的每一值,前一次累积后的值将作为下一次累积的初始值,把通过累积得到的最终值推送给输出流。注意,reduce操作符只会在源 Observable 发出结束通知后发出一个值。

源 Observable 上发出的值都会被累积函数处理。如果提供了初始值,这个值将成为整个累积过程的初始值,如果没有提供的话,从源 Observable 发出的第一个值就是整个累积过程的初始值。

返回值 Observable 把源 Observable 上的值都经过累积函数计算后得到的值作为值发送的流。

示例

</>复制代码

  1. const clicksInFiveSeconds = fromEvent(document, "click")
  2. .takeUntil(interval(5000));
  3. const ones = clicksInFiveSeconds.mapTo(1);
  4. const seed = 0;
  5. const count = ones.reduce((acc,cur) => acc + cur, seed);
  6. count.subscribe(v => console.log(v));

scan

实例方法

在输入流上应用一个累积函数,每一次累积的结果都发送给输出流,累积时可以接受一个可选的初始值。 和reduce操作符类似,不同的是会把每一次累积的结果都发送出去。

返回值 Observable 输出累积值的流。

示例

</>复制代码

  1. fromEvent(document, "click")
  2. .mapTo(1)
  3. .scan((acc,cur) => acc + cur, 0)
  4. .subscribe(v => console.log(v))

操作符就介绍到这里,都是一些非常非常非常常用的,另外一些没有介绍到的并非没有用,需要的请自行搜索,通过操作符之间的相互组合我们可以实现非常高效便捷的数据处理。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97261.html

相关文章

  • Spring Boot 2 快速教程:WebFlux 快速入门(二)

    摘要:响应式编程是基于异步和事件驱动的非阻塞程序,只是垂直通过在内启动少量线程扩展,而不是水平通过集群扩展。三特性常用的生产的特性如下响应式编程模型适用性内嵌容器组件还有对日志消息测试及扩展等支持。 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 02:WebFlux 快速入门实践 文章工程: JDK...

    gaara 评论0 收藏0
  • css相关 - 收藏集 - 掘金

    摘要:在正式前端一些小细节前端掘金英文原文,翻译未来的太让人兴奋了一方面,是全新的页面布局方式另一方面,是酷炫的滤镜颜色等视觉效果。老司机教你更好的进行编程个技巧前端掘金并不总是容易处理。 CSS3 实现文字流光渐变动画 - 前端 - 掘金来自百度前端技术学院的实践任务:有趣的鼠标悬浮模糊效果,参考:http://ife.baidu.com/course/d...,用CSS3实现了一下,顺便...

    molyzzx 评论0 收藏0
  • 命令响应(一)

    摘要:响应式命令式这两种编程风格的思维方式是完全相反的。第二种方式是工人主动去找工人索取生产手机所要的零件,然后生产一台完整的手机,这两种方式就对应的响应式和命令式。 angular2中内置了rxjs,虽然框架本身并没有强制开发者使用响应式风格来组织代码,但是从框架开发团队的角度可以看出他们必然是认同这种编程风格的。rxjs本质是基于函数式编程的响应式风格的库,函数式相对于面向对象来说更加抽...

    JayChen 评论0 收藏0
  • 【CuteJavaScript】Angular6入门项目(3.编写服务和引入RxJS)

    摘要:发布通过回调方法向发布事件。观察者一个回调函数的集合,它知道如何去监听由提供的值。 本文目录 一、项目起步 二、编写路由组件 三、编写页面组件 1.编写单一组件 2.模拟数据 3.编写主从组件 四、编写服务 1.为什么需要服务 2.编写服务 五、引入RxJS 1.关于RxJS 2.引入RxJS 3.改造数据获取方式 六、改造组件 1.添...

    RebeccaZhong 评论0 收藏0

发表评论

0条评论

CoderBear

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<