rxJSのパイプとは


103

私は基本的なコンセプトを持っていると思いますが、いくつかの曖昧さがあります

したがって、一般的に、これは私がobservableを使用する方法です:

observable.subscribe(x => {

})

データをフィルタリングしたい場合は、これを使用できます:

import { first, last, map, reduce, find, skipWhile } from 'rxjs/operators';
observable.pipe(
    map(x => {return x}),
    first()
    ).subscribe(x => {

})

私もこれを行うことができます:

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';

observable.map(x => {return x}).first().subscribe(x => {

})

だから私の質問は:

  1. 違いはなんですか?
  2. 違いがないのに、なぜ機能パイプが存在するのですか?
  3. これらの関数に異なるインポートが必要なのはなぜですか?

1
カスタムの非ネイティブ演算子用だと言っていましたが、それが正しいかどうかさえわかりません。DOESはpipe()、あなたが作成することを事業者に渡してみましょうか?
zero298 2018

回答:


69

「pipable」(以前の「lettable」)演算子は RxJS5.5以降の演算子の現在の推奨される使用方法です。

公式ドキュメントhttps://rxjs.dev/guide/v6/pipeable-operatorsを読むことを強くお勧めします

主な違いは、カスタム演算子を作成する方が簡単でありObservable、2つの異なるパーティが同じ名前の演算子を作成したい場合に衝突を引き起こす可能性のあるグローバルオブジェクトを変更せずに、ツリーシェイクが容易になることです。

importオペレーターごとに個別のステートメントを使用'rxjs/add/operator/first'することは、より小さなアプリバンドルを作成する方法でした。RxJSライブラリ全体ではなく、必要な演算子のみをインポートすることで、バンドルの合計サイズを大幅に削減できます。ただし、'rxjs/add/operator/first'コードに本当に必要なため、またはコードをリファクタリングするときに削除するのを忘れたため、コンパイラはインポートしたかどうかを認識できません。これは、未使用のインポートが自動的に無視されるpipable演算子を使用する利点の1つです。


1
あなたの肯定についてunused imports are ignored automatically、現在、IDEには未使用のインポートを削除するプラグインがあります。
silvanasono 2018

誰もがこれらのIDEやプラグインを使用しているわけではなく、多くの人が基本的なテキストエディタを使用しています。おそらくほとんどの場合、チームの全員が私たちと同じIDE /プラグインセット/テキストエディタを使用しているという声明を伝えることはできません。
AdamFaryna19年

3
@AdamFaryna確かに、一部のチームは紙にコードを書くこともありますが、最新のツールが利用できるのであれば、なぜそうするのでしょうか。特に重要なプラグインなしでテキストエディタを使用することは、紙にコードを書くことに似ています。あなたはそれを行うことができますが、なぜまともなチーム/開発者がそれを行うのでしょうか
DenesPapp19年

@DenesPappコードエディタは、人々が生産的な方法で使用できる限り、問題ではありません。それ以外は、個人的な好みです。紙にコードを書くこととの類似性は不正確です。紙にコードを実行することはできませんが、任意のテキストエディタで記述されたコードは実行できます。
AdamFaryna19年

1
あなたがすることができますが、インストールする必要があり@perymimonrxjs-compatパッケージgithub.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/...
マーティン

16

パイプ方式

元のドキュメントによると

pipable演算子は、関数がobservableを入力として受け取り、別のobservableを返します。previousobservableは変更されないままです。

pipe(...fns: UnaryFunction<any, any>[]): UnaryFunction<any, any>

元の投稿

パイプとはどういう意味ですか?

つまり、以前にobservableのインスタンスで使用した演算子はすべて、の下の純粋関数として使用できますrxjs/operators。これにより、オペレーターの構成の構築やオペレーターの再利用が非常に簡単になります。あらゆる種類のプログラミング体操に頼る必要はありません。カスタムのオブザーバブルを拡張するオブザーバブルを作成し、リフトを上書きして独自のカスタムのものを作成する必要があります。

const { Observable } = require('rxjs/Rx')
const { filter, map, reduce,  } = require('rxjs/operators')
const { pipe } = require('rxjs/Rx')

const filterOutWithEvens = filter(x => x % 2)
const doubleByValue = x => map(value => value * x);
const sumValue = reduce((acc, next) => acc + next, 0);
const source$ = Observable.range(0, 10)

source$.pipe(
  filterOutWithEvens, 
  doubleByValue(2), 
  sumValue)
  .subscribe(console.log); // 50

@VladKutsはコードを変更し、属性を指定します。ご不便をおかけして申し訳ありません。
チャナカウィーラシンゲ

ありがとうございます。パイプ可能な演算子を関数参照として格納し、pipe()呼び出しで使用できることに気づいていませんでした。これは、常にインラインで実行するよりもはるかにクリーンです。
アレックス。A

9

私が思いついた良い要約は次のとおりです。

ストリーミング操作(マップ、フィルター、リデュースなど)をコア機能(サブスクライブ、パイピング)から切り離します。チェーンの代わりに配管操作を行うことで、Observableのプロトタイプを汚染せず、ツリーの揺れを容易にします。

https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md#whyを参照してください

ドットチェーンのパッチが適用された演算子の問題は次のとおりです。

パッチ演算子をインポートするライブラリは、そのライブラリのすべてのコンシューマーのObservable.prototypeを拡張し、ブラインド依存関係を作成します。ライブラリがそれらの使用法を削除すると、彼らは無意識のうちに他のすべての人を壊します。パイプ可能では、必要な演算子を、それらを使用する各ファイルにインポートする必要があります。

プロトタイプに直接パッチを適用したオペレーターは、ロールアップやWebpackなどのツールで「ツリーシェイク可能」ではありません。パイプ可能な演算子は、モジュールから直接引き込まれた関数であるためです。

アプリにインポートされている未使用の演算子は、ビルドツールやlintルールでは確実に検出できません。つまり、スキャンをインポートしても使用を停止しても、出力バンドルに追加されたままになります。パイプ可能な演算子を使用すると、それを使用していない場合、lintルールがそれを取得できます。

機能的な構成は素晴らしいです。独自のカスタム演算子の作成がはるかに簡単になり、rxjsの他のすべての演算子と同じように機能して表示されるようになりました。Observableを拡張したり、リフトをオーバーライドしたりする必要はもうありません。


8

違いはなんですか? あなたの例でわかるように、主な違いはソースコードの読みやすさを改善することです。あなたの例には2つの関数しかありませんが、関数が12個あると想像してみてください。その後、それは次のようになります

function1().function2().function3().function4()

特に関数の内部を埋めているときは、本当に醜くなり、読みにくくなります。その上、Visual Studioコードのような特定のエディターでは、140行を超える長さは許可されていません。しかし、それが次のようになる場合。

Observable.pipe(
function1(),
function2(),
function3(),
function4()
)

これにより、読みやすさが大幅に向上します。

違いがないのに、なぜ機能パイプが存在するのですか? PIPE()関数の目的は、取得するすべての関数をまとめて、observableを返すことです。最初はobservableを取り、次にそのobservableはpipe()関数全体で、その内部で使用される各関数によって使用されます。

最初の関数はオブザーバブルを取得して処理し、その値を変更して次の関数に渡します。次に、次の関数は最初の関数のオブザーバブルの出力を取得して処理し、次の関数に渡します。その後、すべての関数が実行されるまで続行されます。 pipe()関数内でそのオブザーバブルを使用すると、最終的に処理されたオブザーバブルが得られます。最後に、subscribe()関数を使用してobservableを実行し、そこから値を抽出できます。元のオブザーバブルの値は変更されないことを忘れないでください。 

これらの関数に異なるインポートが必要なのはなぜですか? インポートは、関数がrxjsパッケージのどこで指定されているかによって異なります。こんなふうになります。すべてのモジュールはAngularのnode_modulesフォルダーに保存されます。「モジュール」から{クラス}をインポートします。

例として次のコードを取り上げましょう。私はそれをstackblitzで書いたところです。したがって、何も自動的に生成されたり、他の場所からコピーされたりすることはありません。rxjsのドキュメントに記載されている内容をコピーして、それを読むことができるのに意味がありません。ドキュメントを理解していなかったので、ここでこの質問をしたと思います。 

  • それぞれのモジュールからインポートされたパイプ、監視可能、のマップクラスがあります。 
  • クラスの本体では、コードに示されているように、Pipe()関数を使用しました。 
  • Of()関数は、サブスクライブ時に順番に番号を発行するobservableを返します。

  • Observableはまだサブスクライブされていません。

  • Observable.pipe()のように使用した場合、pipe()関数は指定されたObservableを入力として使用します。

  • 最初の関数map()関数は、そのObservableを使用して処理し、処理されたObservableをpipe()関数に戻します。

  • 次に、処理されたObservableは、存在する場合は次の関数に渡されます。

  • そして、すべての関数がObservableを処理するまで、そのように続きます。

  • 最後に、Observableがpipe()関数によって変数に返されます。次の例では、そのobsです。

Observableにあるのは、オブザーバーがサブスクライブしない限り、値を出力しないということです。そこで、subscribe()関数を使用して、このObservableをサブスクライブし、サブスクライブするとすぐにサブスクライブしました。of()関数は値の出力を開始し、pipe()関数を介して処理され、最後に最終結果を取得します。たとえば、1はof()関数から取得され、1はmap()関数に1が追加されます。そして戻ってきました。その値は、subscribe(function(argument){})関数内の引数として取得できます。

印刷したい場合は、

subscribe( function (argument) {
    console.log(argument)
   } 
)
    import { Component, OnInit } from '@angular/core';
    import { pipe } from 'rxjs';
    import { Observable, of } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent implements OnInit  {
    
      obs = of(1,2,3).pipe(
      map(x => x + 1),
      ); 
    
      constructor() { }
    
      ngOnInit(){  
        this.obs.subscribe(value => console.log(value))
      }
    }

https://stackblitz.com/edit/angular-ivy-plifkg

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.