rxjs中Observable.lift和Observable.pipe有什么区别?

时间:2018-02-22 11:47:41

标签: javascript angular rxjs

The docsObservable.lift(operator: Operator)定义为:

  

使用此Observable作为源,创建一个新的Observable   传递的运算符被定义为新的可观察运算符。

Observable.pipe(operations: ...*) as:

  

用于将功能操作符拼接成链。返回   已经调用了所有运算符的可观察结果   他们被传递了。

很明显.pipe可以接受多个运算符,而.lift则不能。但是pipe也可以接受单个运算符,因此这不是唯一的区别。仅从文档中我不清楚它们是什么以及它们存在的原因。 有人可以解释每个功能的用途,以及何时应该使用它们?

到目前为止的观察

以下代码(打字稿):

let myObservable = Observable.of(1, 2, 3);
let timesByTwoPiped = myObservable.pipe(map(n => n * 2));
let timesByTwoLift = myObservable.lift(new TimesByTwoOperator());

timesByTwoPiped.subscribe(a => console.log('pipe:' + a));
timesByTwoLift.subscribe(a => console.log('lift:' + a));

TimesByTwoOperator

class TimesByTwoOperator implements Operator<number, number> {
  call(subscriber: Subscriber<number>, source: Observable<number>): void | Function | AnonymousSubscription {
    source.subscribe(n => {
      subscriber.next(n * 2);
    });
  }
}

似乎使用.lift.pipe来获得相同的结果。这个实验表明,我认为升降机和管道都可以用来实现同样的目的,尽管在这种情况下管道版本更加简洁。

由于传递给Operator的{​​{1}}类型被赋予对源可观察和订阅的完全访问权限,因此可以实现强大的功能;例如保持状态。但我知道.lift也可以实现同样的权力,例如使用buffer operator

我仍然不清楚为什么它们都存在以及各自的设计原因。

3 个答案:

答案 0 :(得分:3)

我已经在这个主题上找到了一个很好的深入讨论,以及在这里删除Observable.lift以支持Observable.pipe的潜在想法: https://github.com/ReactiveX/rxjs/issues/2911

TL; DR

  

现在让我们来比较&#34; pure&#34;电梯和管道签名:

// I'm intentionally ignoring pipe's multiple operator function args,
// since we could redefine lift to also take multiple operator functions
type Operator = <T, R>(sink: Observer<R>) => Observer<T>
type lift = <T, R>(src: Observable<T>, op: Operator) => Observable<R>;
type pipe = <T, R>(op: Operator) => (src: Observable<T>) => Observable<R>
     
      
  • pipe的运算符函数将Observable映射到Observable
  •   
  • lift的操作员功能将观察者映射到观察者
  •   
     

这只是表达其中任何一个想法的另一种方式:

     
      
  • 从源头到水槽建立一条可观察链
  •   
  • 或构建从接收器到源的观察者链
  •   

答案 1 :(得分:1)

  

有人可以解释这些功能的用途以及何时使用它们吗?

lift()创建一个新的可观察对象,但pipe()不创建。 pipe()遵循功能性编程范例,lift()是面向对象的。

它们都接受功能作为输入参数,但是pipe()的优点是不会创建额外的可观察对象。

当您使用lift()时,会将运算符附加到到新的可观察对象上,并且当订阅此新的可观察对象时,将附加的操作符 intercepts < / em>订阅之前的流。

这与pipe()的工作方式不同,因为操作员返回相同的可观察值将不会对原始可观察值产生任何变化。

pipe()是在lift()之后引入的,我认为这是链接运算符的首选方式。

答案 2 :(得分:0)

ADT(代数数据类型 - 替代 OOP 类)

Lifting 通常与 Monad 一起使用。 RXJS 库本身 - 代表 Monad(和其他一堆)ADT。

“lift”来自 FP 和 ADT。 以下是“提升”一词的含义的描述性解释: https://wiki.haskell.org/Lifting

TLDR:

const sum = a => b => a + b;

console.log(sum(2)(3)); // 5

// and now we need to reuse our "sum" within a Monad level.
// it means we need to "lift" our "sum" function to the Monad level:

// assumption: our Monad - is just an Array


const monad0 = [2];
const monad1 = [3];

// lift1 === fmap
// lift1:: Monad M: (a -> b) -> M a -> M b
const lift1 = f => Ma => [f(Ma[0])];

// lift2:: Monad M: (a -> b) -> M a -> M b -> M c
const lift2 = f => Ma => Mb => [f(Ma[0])(Mb[0])];

// lift3 etc...

console.log(lift2(sum)(monad0)(monad1)); // [5]