[英]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 版本更简洁。
由于传递给.lift
的Operator
类型被授予对源 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.