[英]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.