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/...

相关文章
相关标签/搜索