1.Rxjs基础知识
- 基本概念
- Observable (可观察对象): 表示一个概念,这个概念是一个可调用的未来值或事件的集合。
- Observer (观察者): 一个回调函数的集合,它知道如何去监听由 Observable 提供的值。
- Subscription (订阅): 表示 Observable 的执行,主要用于取消 Observable 的执行。
- Operators (操作符): 采用函数式编程风格的纯函数 (pure function),使用像 map、filter、concat、flatMap 等这样的操作符来处理集合。
- Subject (主体): 相当于 EventEmitter,并且是将值或事件多路推送给多个 Observer 的唯一方式。
- Schedulers (调度器): 用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他。
- RXJS6的变化
- 引入变化
- 总而言之: 类似于创建之类的用的API都是从rxjs引入的,类似于map 之类的操作都是从rxjs/operators引入的
- 如果项目升级不能马上更改完全部相关代码的可安装以下东西,可以暂时不用改代码,可以一点点地改,直到改完后吧这个包卸掉,但是对于rxjs6的rename的operator无效,所以,如果有用到rename的API,必须手动修改
npm install --save rxjs-compat
- 具体例子(按钮点击事件)
<button #click type="button" (click)="clickEvent()">点击</button>
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; import { fromEvent, from } from 'rxjs'; import { filter, map } from 'rxjs/operators'; // import "rxjs/add/Observable/fromEvent"; RXJS6之前的引入方式 // import "rxjs/add/operator/map"; RXJS6之前的引入方式 @Component({ selector: 'app-rxjs-demo', templateUrl: './rxjs-demo.component.html', styleUrls: ['./rxjs-demo.component.css'] }) export class RxjsDemoComponent implements OnInit { @ViewChild('click') button: ElementRef constructor() { } ngOnInit() { } clickEvent() { // 注册并发送事件(RXJS6),静态方法直接调用就可以了 fromEvent(this.button.nativeElement, 'click') .subscribe( () => console.log('Clicked!'), err => console.error(err), () => console.log("结束了") ); // 注册并发送事件(RXJS6之前) // Observable.fromEvent(this.button.nativeElement, 'click') // .subscribe( // () => console.log('Clicked!'), // err => console.error(err), // () => console.log("结束了") // ); // 注册并发送值(RXJS6) from([1, 2, 3, 4]).pipe( filter(e => e % 2 == 0), map(e => e * e) ) .subscribe( e => console.log(e), err => console.error(err), () => console.log("结束了") ) // 注册并发送值(RXJS6之前) // Observable.from([1, 2, 3, 4]) // .filter(e => e % 2 == 0) // .map(e => e * e) // .subscribe( // e => console.log(e), // err => console.error(err), // () => console.log("结束了") // ) } }
-
案例分析
-
在上面的发送事件例子中
-
Subscription(订阅):
subscribe(
() => console.log('Clicked!'),
err => console.error(err),
() => console.log("结束了")
);
-
Subject(主体): (this.button.nativeElement, 'click')
-
Observable(可观察对象) :fromEvent(返回的还是一个Observable)。
-
Observer(观察者): Subscribe内部的函数就是观察者。
() => console.log('Clicked!'), 事件成功的回调函数
err => console.error(err), 事件出现错误的回调函数
() => console.log("结束了") 事件结束的回调函数(要么成功要么失败)
-
- 引入变化
-
拉取与推送(转载)
拉取和推送是两种不同的协议,用来描述数据生产者 (Producer)如何与数据消费者 (Consumer)如何进行通信的。
什么是拉取? - 在拉取体系中,由消费者来决定何时从生产者那接收数据。生产者本身不知道数据是何时交付到消费者手中的。
什么是推送? - 在推送体系中,由生产者来决定何时把数据发送给消费者。消费者本身不知道何时会接收到数据。在当今的JavaScript 世界中,Promises 是最常见的推送体系类型。Promise(生产者) 将一个解析过的值传递给已注册的回调函数(消费者),但不同于函数的是,由 Promise 来决定何时把值“推送”给回调函数。
RxJS 引入了 Observables,一个新的 JavaScript 推送体系。Observable 是多个值的生产者,并将值“推送”给观察者(消费者)。
Function 是惰性的评估运算,调用时会同步地返回一个单一值。
Generator 是惰性的评估运算,调用时会同步地返回零到(有可能的)无限多个值。返回一个iterators,每次的调用会返回一个值。
Promise 是最终可能(或可能不)返回单个值的运算。通过resolve决定值的返回。
Observable 是惰性的评估运算,它可以从它被调用的时刻起同步或异步地返回零到(有可能的)无限多个值。这里的惰性的意义是说,需要调用者去调用才会触发结果的返回。上面的方式promise来说,对于回调函数then是在promise resolve值之后才会调用,否则永远不会调用,不管你的then是否存在,其他几种的话,只要调用就已经会返回值了,不管你何时调用,都会有相应的返回值,而不像promise可以决定这个值什么时候返回,是否返回。
2.angular中的响应式编程
- 响应式编程就是:就是异步数据流编程
- 案例:现在有个搜素框,我输入东西后就开始进行搜索。我想搜索Alibaba,当我输入A的时候就会触发keyup事件去服务器搜索,当我输入AL的时候也会去服务器搜索。这不是我们想要的。我们想输入完Alibaba后去搜索。这里可以设置一个时间间隔,在这个时间间隔内没有再输入东西的时候就去服务器搜索。这个功能用传统的JavaScript实现起来比较麻烦。
- 需要在app,module.ts中引入ReactiveFormsModule
- 创建搜索框
<input [formControl]="searchInput">
- 实现响应式功能
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core'; import { FormControl } from '@angular/forms'; import { debounceTime } from 'rxjs/operators'; @Component({ selector: 'app-rxjs-ng', templateUrl: './rxjs-ng.component.html', styleUrls: ['./rxjs-ng.component.css'] }) export class RxjsNgComponent implements OnInit { searchInput: FormControl = new FormControl(); constructor() { this.searchInput.valueChanges.pipe( debounceTime(500)//设置为500毫秒 ) .subscribe(stockCode => this.getInputValue(stockCode));//stockCode就是用户输入的值 } ngOnInit() { } getInputValue(value: string) { console.log(value); } }
3.通过响应式编程与管道为在线竞拍提供一个商品过滤功能
- 为商品组件添加一个商品搜索输入框
<div class="row"> <div class="col-sm-12"> <div class="form-group"> <input class="form-control" placeholder="请输入商品名称" [formControl]="titleFilter"> </div> </div> </div>
import { Component, OnInit } from '@angular/core'; import { ProductService, Products } from 'src/shared/product.service'; import { FormControl } from '@angular/forms'; @Component({ selector: 'app-product', templateUrl: './product.component.html', styleUrls: ['./product.component.css'] }) export class ProductComponent implements OnInit { // 声明变量接收商品信息 public products: Products[]; // 定义关键词formControl public titleFilter: FormControl = new FormControl(); // 声明关键词变量 private keyword: string; // 注入商品服务 constructor(private _ProductService: ProductService) { // 监听商品输入框值变化 this.titleFilter.valueChanges .subscribe( value => this.keyword = value ); } ngOnInit() { // 使用商品服务的getProducts()方法获取商品信息 this.products = this._ProductService.getProducts(); } }
- 自定义商品过滤管道(ng g p pipe/filter)
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'filter' }) export class FilterPipe implements PipeTransform { // filterField : 根据商品什么字段过滤 // keyword : 商品关键词 transform(list: any[], filterField?: string, keyword?: string): any { // 判断是否输入关键词 if (!filterField || !keyword) { return list; } // 返回与关键词相对应的值 return list.filter(item => { const filedValue = item[filterField]; return filedValue.indexOf(keyword) >= 0; }); } }
- 在商品组件中使用管道
<div class="row"> <div class="col-sm-12"> <div class="form-group"> <input class="form-control" placeholder="请输入商品名称" [formControl]="titleFilter"> </div> </div> </div> <div class="row"> <!-- 引入商品过滤管道,根据商品名称过滤商品 --> <div class="col-lg-4 col-md-4 col-xs-12" *ngFor="let product of products | filter:'name':keyword"> <div class="thumbnail"> <img src={{product.img}} alt=""> <div class="caption"> <h3 class="pull-right">¥{{product.price}}</h3> <!-- 点击商品名称跳转到商品详情页,传递两个参数id,name --> <a [routerLink]="[ '/detialproduct', product.id , product.name ]"> <h3>{{product.name}}</h3> </a> <span class="product-desc">{{product.desc}}</span> <p> <!--星级评价的rating属性由产品的rating属性传进去--> <app-stars [rating]="product.rating"></app-stars> <span> {{product.rating | number: '1.1-1'}} 星</span> </p> </div> </div> </div> </div>