如果对 RxJS 的 operators (操作符) 不熟悉的话,建议读者在阅读本文时,先阅读 RxJS - Observables,observers 和 operators 简介 这篇文章。
基础知识
什么是 Operator
Operator 是一个函数,它接收一个 Observable 对象,然后返回一个新的 Observable 对象。当我们订阅新返回的 Observable 对象时,它内部会自动订阅前一个 Observable 对象。
如何为 Observable 添加操作符
比较常见的有以下三种方式:
1.使用 ES7 函数绑定运算符 ::
(可使用 BabelJS 进行转换)
someObservable::mySimpleOperator(x => x + '!');
2.继承 Observable 类,并重写 lift()
方法
class MyObservable extends Observable { lift(operator) { const observable = new MyObservable(); //<-- important part here observable.source = this; observable.operator = operator; return observable; } // put it here .. or .. customOperator() { /* do things and return an Observable */ } } // ... put it here... MyObservable.prototype.mySimpleOperator = mySimpleOperator;
3.直接添加到 Observable.prototype
对象上
Observable.prototype.mySimpleOperator = mySimpleOperator; someObservable.mySimpleOperator(x => x + '!');
自定义 toJSON 操作符
当我们使用 Angular HTTP 服务时,我们需要调用 Response 对象的 json()
方法把服务端接口返回的数据,转换为 JSON 对象,例如:
this.http.get('https://api.github.com/orgs/angular/members?page=1&per_page=5') .map(res => res.json());
对于每个接口,我们都需要调用 map 操作符对返回的数据做对应的处理。那能不能简化这个操作呢?答案是有的,我们可以通过自定义一个 toJSON 操作符来简化上述的过程。具体实现如下:
function toJSON<T>(): Observable<T> { return this.map(( response : Response ) => response.json()); }
上面代码中,this
指向源 Observable 对象,即调用 http 对象的 get()
方法后返回的 Observable 对象。此外我们直接返回了调用 map()
操作符后新建的 Observable 对象。
为了能够使用我们自定义的 toJSON
操作符,我们需要把它添加到 Observable 的原型对象上:
Observable.prototype.toJSON = toJSON;
最后的一件事是我们需要添加以下的定义:
declare module "rxjs/Observable" { interface Observable<T> { toJSON : typeof toJSON; } }
完整示例
custom-operators.ts
import { Observable } from 'rxjs/Observable'; function toJSON<T>(): Observable<T> { return this.map(( response : Response ) => response.json()); } Observable.prototype.toJSON = toJSON;
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpModule } from "@angular/http"; import { AppComponent } from './app.component'; import './custom-operators'; @NgModule({ declarations: [ AppComponent ],imports: [ BrowserModule,HttpModule ],providers: [],bootstrap: [AppComponent] }) export class AppModule { }
app.component.ts
import { Observable } from 'rxjs/Observable'; import { Component,OnInit } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; interface Member { id: string; login: string; avatar_url: string; } @Component({ selector: 'app-root',template: ` <h3>Angular Orgs Members</h3> <ul *ngIf="members"> <li *ngFor="let member of members;"> <p> <img [src]="member.avatar_url" width="48" height="48"/> ID:<span>{{member.id}}</span> Name: <span>{{member.login}}</span> </p> </li> </ul> ` }) export class AppComponent implements OnInit { members: Member[]; constructor(private http: Http) { } ngOnInit() { this.http.get(`https://api.github.com/orgs/angular/members?page=1&per_page=5`) .toJSON<Member[]>() // 使用自定义 toJSON 操作符 .subscribe(data => { if (data) this.members = data; }); } }
typings.d.ts
// src/typings.d.ts (在该文件下,新增以下内容) export declare function toJSON<T>(): Observable<T>; declare module "rxjs/Observable" { interface Observable<T> { toJSON : typeof toJSON; } }