博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【响应式编程的思维艺术】 (5)Angular中Rxjs的应用示例
阅读量:6495 次
发布时间:2019-06-24

本文共 5353 字,大约阅读时间需要 17 分钟。

目录

本文是这篇文章的学习笔记。

示例代码托管在:

博客园地址:

华为云社区地址:

1354575-20190220210230094-2135844697.jpg

一. 划重点

  • RxJS-DOM

    原文示例中使用这个库进行DOM操作,笔者看了一下,400多星,而且相关的资料很少,所以建议理解思路即可,至于生产环境的使用还是三思吧。开发中Rxjs几乎默认是和Angular技术栈绑定在一起的,笔者最近正在使用ionic3进行开发,本篇将对基本使用方法进行演示。

  • 冷热Observable

    • 冷Observable从被订阅时就发出整个值序列
    • 热Observable无论是否被订阅都会发出值,机制类似于javascript事件。
  • 涉及的运算符

    bufferWithTime(time:number)-每隔指定时间将流中的数据以数组形式推送出去。

    pluck(prop:string)- 操作符,提取对象属性值,是一个柯里化后的函数,只接受一个参数。

二. Angular应用中的Http请求

Angular应用中基本HTTP请求的方式:

import { Injectable } from '@angular/core';import { Observable, of } from 'rxjs';import { MessageService } from './message.service';//某个自定义的服务import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';@Injectable({  providedIn: 'root'})export class HeroService {  private localhost = 'http://localhost:3001';  private all_hero_api = this.localhost + '/hero/all';//查询所有英雄  private query_hero_api = this.localhost + '/hero/query';//查询指定英雄  constructor(private http:HttpClient) {  }    /*一般get请求*/  getHeroes(): Observable
>{ return this.http.get
(this.all_hero_api,{observe:'response'}); } /*带参数的get请求*/ getHero(id: number): Observable
>{ let params = new HttpParams(); params.set('id', id+''); return this.http.get
(this.query_hero_api,{params:params,observe:'response'}); } /*带请求体的post请求,any可以自定义响应体格式*/ createHero(newhero: object): Observable
>{ return this.http.post
>(this.create_hero_api,{data:newhero},{observe:'response'}); } }

express中写一些用于测试的虚拟数据:

var express = require('express');var router = express.Router();/* GET home page. */router.get('/all', function(req, res, next) {  let heroes = [{    index:1,    name:'Thor',    hero:'God of Thunder'  },{    index:2,    name:'Tony',    hero:'Iron Man'  },{    index:3,    name:'Natasha',    hero:'Black Widow'  }]  res.send({     data:heroes,     result:true  })});/* GET home page. */router.get('/query', function(req, res, next) {  console.log(req.query);  let hero= {    index:4,    name:'Steve',    hero:'Captain America'  }  res.send({     data:hero,     result:true  })});/* GET home page. */router.post('/create', function(req, res, next) {  console.log(req.body);  let newhero = {     index:5,     name:req.body.name,     hero:'New Hero'  }  res.send({     data:newhero,     result:true  })});module.exports = router;

在组件中调用上面定义的方法:

sendGet(){ this.heroService.getHeroes().subscribe(resp=>{   console.log('响应信息:',resp);   console.log('响应体:',resp.body['data']); })}sendQuery(){this.heroService.getHero(1).subscribe(resp=>{  console.log('响应信息:',resp);  console.log('响应体:',resp.body['data']);})}sendPost(){this.heroService.createHero({name:'Dash'}).subscribe(resp=>{  console.log('响应信息:',resp);  console.log('响应体:',resp.body['data']);})}

控制台打印的信息可以看到后台的虚拟数据已经被请求到了:

1354575-20190220210302508-907545626.png

三. 使用Rxjs构建Http请求结果的处理管道

3.1 基本示例

尽管看起来Http请求的返回结果是一个可观测对象,但是它却没有map方法,当需要对http请求返回的可观测对象进行操作时,可以使用pipe操作符来实现:

import { Observable, of, from} from 'rxjs';import { map , tap, filter, flatMap }from 'rxjs/operators';/*构建一个模拟的结果处理管道*map操作来获取数据*tap实现日志*flatMap实现结果自动遍历*filter实现结果过滤*/getHeroes$(): Observable
>{ return this.http.get
(this.all_hero_api,{observe:'response'}) .pipe( map(resp=>resp.body['data']), tap(this.log), flatMap((data)=>{return from(data)}), filter((data)=>data['index'] > 1) );}

很熟悉吧?经过处理管道后,一次响应中的结果数据被转换为逐个发出的数据,并过滤掉了不符合条件的项:

1354575-20190220210322403-1871146885.png

3.2 常见的操作符

Angular中文网列举了最常用的一些操作符,有非常详细的示例及说明,且均配有形象的大理石图,建议先整体浏览一下有个印象,有需要的读者可以每天熟悉几个,很快就能上手,运算符的使用稍显抽象,且不同运算符的组合使用在流程控制和数据处理方面的用法灵活多变,也是有很多套路的,开发经验需要慢慢积累。

1354575-20190220210338810-1901623898.png

四. 冷热Observable的两种典型场景

原文中提到的冷热Observable的差别可以参考这篇文章,概念本身并不难理解。

4.1 shareReplay与请求缓存

开发中常会遇到这样一种场景,某些集合型的常量,完全是可以复用的,通常开发者会将其进行缓存至某个全局单例中,接着在优化阶段,通过增加一个if判断在请求之前先检查缓存再决定是否需要请求,Rxjs提供了一种更优雅的实现。

先回顾一下上面的http请求代码:

getHeroes(): Observable
>{ return this.http.get
(this.all_hero_api,{observe:'response'});}

http请求默认返回一个冷Observable,每当返回的流被订阅时就会触发一个新的http请求,Rxjs中通过shareReplay( )操作符将一个可观测对象转换为热Observable(注意:shareReplay( )不是唯一一种可以加热Observable的方法),这样在第一次被订阅时,网络请求被发出并进行了缓存,之后再有其他订阅者加入时,就会得到之前缓存的数据,运算符的名称已经很清晰了,【share-共享】,【replay-重播】,是不是形象又好记。对上面的流进行一下转换:

getHeroes$(): Observable
>{ return this.http.get
(this.all_hero_api,{observe:'response'}) .pipe( map(resp=>resp.body['data']), tap(this.log), flatMap((data)=>{return from(data)}), filter((data)=>data['index'] > 1), shareReplay() // 转换管道的最后将这个流转换为一个热Observable ) }

在调用的地方编写调用代码:

sendGet(){     let obs = this.heroService.getHeroes$();     //第一次被订阅     obs.subscribe(resp=>{       console.log('响应信息:',resp);     });    //第二次被订阅     setTimeout(()=>{       obs.subscribe((resp)=>{         console.log('延迟后的响应信息',resp);       })     },2000)}

通过结果可以看出,第二次订阅没有触发网络请求,但是也得到了数据:

1354575-20190220210402394-145546873.png

网络请求只发送了一次(之前的会发送两次):

1354575-20190220210415924-1632717006.png

4.2 share与异步管道

这种场景笔者并没有进行生产实践,一是因为这种模式需要将数据的变换处理全部通过pipe( )管道来进行,笔者自己的函数式编程功底可能还不足以应付,二来总觉得很多示例的使用场景很牵强,所以仅作基本功能介绍,后续有实战心得后再修订补充。Angular中提供了一种叫做异步管道的模板语法,可以直接在*ngFor的微语法中使用可观测对象:

  • {
    {contact.name}}
  • {
    {contact.name}}

示例:

this.contacts = http.get('contacts.json')                    .map(response => response.json().items)                    .share();setTimeout(() => this.contacts2 = this.contacts, 500);

五. 一点建议

一定要好好读官方文档。

转载于:https://www.cnblogs.com/dashnowords/p/10409224.html

你可能感兴趣的文章
Python ( 1 ) ----- 简介
查看>>
[linux基础学习]run level
查看>>
第七周学习总结
查看>>
一步步的教你安装UChome (UChome 安装教程)
查看>>
[DeeplearningAI笔记]序列模型1.5-1.6不同类型的循环神经网络/语言模型与序列生成...
查看>>
P2533 [AHOI2012]信号塔
查看>>
Android电话拨号器(uri格式)与四种设置点击事件的方法
查看>>
java web中对json的使用
查看>>
TYVJ P1051 选课 Label:多叉转二叉&&树形dp(虐心♥)
查看>>
将数据库中提取出来的数据在后台进行分页处理
查看>>
bzoj1034
查看>>
百度地图 鼠标绘制,获取矩形,多边形的顶点经纬度
查看>>
回文树模板
查看>>
struts2之防止表单重复提交
查看>>
【转】Netty系列之Netty并发编程分析
查看>>
cf591d
查看>>
图片存储系统TFS
查看>>
MYSQL备份与恢复
查看>>
贪心/数学 Codeforces Round #212 (Div. 2) A. Two Semiknights Meet
查看>>
Python类__call__()方法
查看>>