rxjs5升級 rx.js6 中的函數式深刻

最近組內的angular在作4->6的升級,這當中也涉及到了rxjs的升級。rxjs升級guide連接如下是記錄的一些rxjs的升級小tips前端

6版本有很是多的break points,總結下來爲如下三點:git

  1. 比較多的引用路徑變動
  2. 一些方法,函數增棄
  3. chainable==>pipeable

以上幾點,在具體實踐上,1和2根據api,以及rx提供的升級檢查工具,都能比較愉快的完成,但比較有意義的第3點,做爲一個對函數式編程感興趣的前端碼農,固然要研究一下原委。github

其實1和2都有點爲第三點服務的意思,咱們先簡單說下1和2。引用路徑的變動,意味着源碼目錄結構的調整(這些你們能夠下載源碼,自行看下);同時,原來的rx也採用了和underscore、lodash同樣的導出方式,在寫法上,知足chainable,因此用rx5時,咱們是這樣寫的:編程

var Rx = require('rxjs');
     const Observable = Rx.Observable;
     Observable.range(1,10)
         .filter(x => x % 2 === 0)
         .map(x => x + x)
         .subscribe(x=> console.log(x))

v5的rx導出了一個核心對象Observable以及若干的附屬類型對象,而後方法(自有方法(create、subscribe等),以及一些經常使用的操做符(map、fileter等))定義在這些對象的prototype上,因此這種定義方式搞起鏈式調用就666,這種實現不影響其本質上的函數式,但在寫法上實際上是面向對象的僞函數式,但可是奇奇怪怪的,總是搞對象是什麼鬼,說好的FP呢。api

因此這也是今天要說的一個重點,chainable-->pipeable的實現,是rx此次版本升級最根本的地方。在內部實現上,把原有的操做符都函數化,同時在Observable上新增了pipe方法,如下是pipe.ts中的pipe實現安全

export function pipe<T, R>(...fns: Array<UnaryFunction<T, R>>): UnaryFunction<T, R> {
  return pipeFromArray(fns);
}

/* @internal */
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);
  };
}

熟悉FP的同窗會發現,這個pipe實際上是一個從左向右執行的compose,只不過它接受的第一個參數是this,即當前Observable實例,因此咱們第一個例子在v6中得這麼寫:ide

import { range } from 'rxjs/observable/range';
import { map, filter } from 'rxjs/operators';


range(0, 10).pipe(
    filter(x => x % 2 === 0),
    map(x => x + x)
).subscribe(x=> console.log(x))

上例pipe作的事情等同於:mapFn(filterFn(range(0,10)))函數式編程

chainable==>到pipeable,在寫法上是一次更加完全的函數式實踐。函數

固然這種方法->函數的更改,還有一些更大的好處:工具

  1. 打包時的按需引入,tree-shake
  2. 更好的用戶自定義:更安全(避免對象prototype定義的全局污染),更方便
  3. 寫法上更函函數式:方便用戶進行函數的compose,curry操做,呼應2的更方便的自定義

其它更詳盡的點,可參考:

rx團隊的說明

原文來自:https://zhuanlan.zhihu.com/p/...

相關文章
相關標籤/搜索