RxJS 5.5 在上周已经发布了 beta.7 版本,在 5.5 中 RxJS 引入了 lettable operator
这一个新特性。依靠这个特性,RxJS 中的流与操做符能够用更加 FP 的风格组合起来。webpack
在以前版本的 RxJS 5 中,操做符经过 dot chaining 的方式进行组合。在考虑 bundle size 的场合,RxJS 的操做符每每以git
import "rxjs/add/operator/SOME_OPERATOR"
(instace operator)import "rxjs/add/observable/SOME_OPERATOR"
(static operator)的方式加入应用程序中。经过这种方法,避免了把完整的 RxJS 所有打包。github
这种 rxjs/add
风格的引入,至关于在 RxJS 库外动态地将操做符加入 Observable
和 Observable.prototype
当中。这也就使得 RxJS 几乎不能受益于 webpack 2 或者 rollup 的 tree-shaking。web
此外,若是没有使用引入的操做符,TypeScript、Flow 或者各类 linter 是不会所以报错的。考虑到 RxJS 中琳琅满目的操做符,不少时候会在编码过程当中不断更换操做符,有时候是会忘记删除引入的操做符,致使 bundle size 的增长。typescript
lettable operator
这个名字是 RxJS 社区中的黑话,RxJS 社区中有 issue 在讨论是否是要改一个对初学者更友好的名字。函数
lettable operator
须要配合 Observable.prototype.pipe
一块儿使用,下面来看一个使用 lettable operator
的例子:oop
import { range } from 'rxjs/observable/range';
import { map, filter, scan } from 'rxjs/operators';
const source$ = range(0, 10);
source$.pipe(
filter(x => x % 2 === 0),
map(x => x + x),
scan((acc, x) => acc + x, 0)
)
.subscribe(x => console.log(x))复制代码
相对的,dot chaining 风格的写法以下:ui
import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/range";
import "rxjs/add/operator/map";
import "rxjs/add/operator/filter";
import "rxjs/add/operator/scan";
const source$ = Observable.range(0, 10);
source$
.filter(x => x % 2 === 0)
.map(x => x + x),
.scan((acc, x) => acc + x, 0)
.subscribe(x => console.log(x));复制代码
以 lettable operator
构成的 pipeline 要比 dot chaining 更贴近于如今流行的 FP 风格。更重要的是,这种方法在引入操做符时比 dot chaining 的 rxjs/add/*
风格方便实用得多。this
所以,也有相关的 issue 在讨论是否将 rxjs/add/*
风格的引入方式在 6.0 中发布到另外的 NPM package 中。编码
Observable.prototype.pipe
的代码以下:
import { pipeFromArray } from './util/pipe';
class Observable<T> implements Subscribable<T> {
pipe<R>(...operations: OperatorFunction<T, R>[]): Observable<R> {
if (operations.length === 0) {
return this as any;
}
return pipeFromArray(operations)(this);
}
}复制代码
在此调用了 ./util/pipe
中由 pipeFromArray
这个高阶函数所返回的函数:
export function pipeFromArray<T, R>(fns: Array<UnaryFunction<T, R>>): UnaryFunction<T, R> {
if (!fns) {
return noop as UnaryFunction<any, any>;
}
if (fns.length === 1) {
return fns[0];
}
return function piped(input: T): R {
return fns.reduce((prev: any, fn: UnaryFunction<T, R>) => fn(prev), input);
};
}复制代码
在这一过程当中,piped
拿到了 Observable 的 this
,并以此做为以后 reduce 过程当中的初始值。
在这个 reduce
方法结束后,就获得了须要的 Observable。