繁体   English   中英

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

[英]What is the difference between Observable.lift and Observable.pipe in rxjs?

文档Observable.lift(operator: Operator)定义为:

创建一个新的 Observable,以这个 Observable 作为源,传递的操作符定义为新的 observable 的操作符。

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

用于将功能运算符拼接成一个链。 返回按传入顺序调用的所有运算符的 Observable 结果。

很明显.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可以达到相同的结果。 这个实验表明我认为 lift 和 pipe 都可以用来实现同样的事情是正确的,尽管在这种情况下 pipe 版本更简洁。

由于传递给.liftOperator类型被授予对源 observable 和订阅的完全访问权限,显然可以用它实现强大的功能; 例如保留 state。 但我知道使用.pipe也可以实现同样的功能,例如使用buffer operator

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

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

TL; DR

现在让我们比较“纯”升力和管道签名:

 // 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的运算符函数将Observer映射到Observer

这只是表达以下两种想法的另一种方式:

  • 建立从源到水槽的可观察链
  • 或者从水槽到源建立一个观察者链

有人可以解释一下这些功能的用途,以及何时应该使用它们?

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

它们都接受函数作为输入参数,但pipe()的优点是没有创建额外的observable。

当您使用lift()单个运算符将附加到新的observable,当订阅此新的observable时,附加的运算符也会在订阅之前拦截该流。

这与pipe()工作原理不同,因为运算符返回相同的observable将不会对原始observable产生任何更改。

lift()之后引入了pipe() ,我认为这是连锁运营商的首选方式。

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

提升通常与 Monads 一起使用。 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 -> c) -> 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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM