簡體   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