RxJS 5.5: 即將到來的 pipeline

RxJS 5.5 在上週已經發布了 beta.7 版本,在 5.5 中 RxJS 引入了 lettable operator 這一個新特性。依靠這個特性,RxJS 中的流與操做符能夠用更加 FP 的風格組合起來。webpack

lettable operator 試圖解決的問題

在以前版本的 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 庫外動態地將操做符加入 ObservableObservable.prototype 當中。這也就使得 RxJS 幾乎不能受益於 webpack 2 或者 rollup 的 tree-shakingweb

此外,若是沒有使用引入的操做符,TypeScript、Flow 或者各類 linter 是不會所以報錯的。考慮到 RxJS 中琳琅滿目的操做符,不少時候會在編碼過程當中不斷更換操做符,有時候是會忘記刪除引入的操做符,致使 bundle size 的增長。typescript

lettable operator 的使用方法

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 中。編碼

lettable operator 的原理

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。

Reference

相關文章
相關標籤/搜索