ワンタイムサブスクリプションを作成する


182

Observable最初に呼び出されたときにすぐに破棄されるへのサブスクリプションを作成する必要があります。

次のようなものはありますか:

observable.subscribeOnce(func);

私の使用例では、エクスプレスルートハンドラーでサブスクリプションを作成し、サブスクリプションがリクエストごとに複数回呼び出されています。

回答:


319

何が必要かについては100%確実ではありませんが、最初の値のみを監視したい場合は、first()またはを使用しますtake(1)

observable.first().subscribe(func);

注:条件が満たされる.take(1)と、.first()両方とも自動的に登録解除されます

RxJS 5.5以降から更新

Codererのコメントより

import { first } from 'rxjs/operators'

observable
  .pipe(first())
  .subscribe(func);

ここに理由があります


33
サブスクリプションは自動的にクリーンアップされますか?
バークレーマルティネス

50
はい、そうです。条件が満たされたら、最初に両方とも登録を解除します。
ブランドン、

20
ドキュメントにサブスクリプションが自動的に破棄されると記載されていないのはなぜですか?
jzig 2016年

17
監視可能なストリームが終了するとサブスクリプションが破棄されるというのは、一般的なRxJSルールです。つまり、ストリームを「短縮」する(または別のタイプのストリームに変換する)演算子は、操作が完了するとソースストリームからサブスクライブ解除されます。これがドキュメントのどこに記載されているか、または記載されているかどうかはわかりません。
ブランドン

37
2018年に誰かがこれに来るなら、あなたは実際observable.pipe(first()).subscribe(func)にどこfirstから来るのかを望んでいますrxjs/operators
Coderer '20

32

RxJSには、今まで出会った中で最高のドキュメントがいくつかあります。以下のリンクをたどると、非常に役立つテーブルマッピングからユースケースを演算子にマッピングできます。:例えば、「私は最初の値を取りたい」ユースケースの下に3つの演算子がありfirstfirstOrDefaultsample

オブザーバブルシーケンスが通知なしで完了した場合、firstオペレーターはサブスクライバーにエラーを通知し、firstOrDefaultオペレーターはサブスクライバーにデフォルト値を提供します。

オペレーターのユースケース検索


3

Observableを1回だけ呼び出したい場合は、Observableからのストリームを待機しないことを意味します。したがって、サブスクリプションを解除する必要がないので、toPromise()代わりにを使用するsubscribe()だけで十分toPromise()です。


非常に興味深い、これも意味我々だけでできること1つのライナーになりたawaitpromise
ルイAlmeda

@LouieAlmedaワンライナーの例を教えてください。
アドレン

こんにちは@AdoRen、私はあなたのためにここに答えでテクニックを説明しました、それが役に立てば幸いです。
Louie Almeda

2

@Brandonの回答を補足first()するには、にBehaviorSubject基づいてを更新するためにを使用することなども不可欠ですObservable。例(未テスト):

var subject = new BehaviorSubject({1:'apple',2:'banana'});
var observable = subject.asObservable();

observable
  .pipe(
    first(), // <-- Ensures no stack overflow
    flatMap(function(obj) {
      obj[3] = 'pear';
      return of(obj);
    })
  )
  .subscribe(function(obj) {
    subject.next(obj);
  });

2

クリーンで便利なバージョン

オブザーバブルをプロミスに変換するM FuatNUROĞLUの驚くべき答えを拡張して、非常に便利なバージョンを示します。

const value = await observable.toPromise();

console.log(value)

これの利点は、別のネストされたブロックを導入することなく、通常の変数のようにその値を使用できることです。

これは、複数のオブザーバブルから複数の値を取得する必要がある場合に特に便利です。清楚な。

const content = await contentObservable.toPromise();
const isAuthenticated = await isAuthenticatedObservable.toPromise();

if(isAuthenticated){
   service.foo(content)
}

もちろん、asyncこのルートを使用する場合は、包含関数を作成する必要があります。.then含まれている関数を非同期にしたくない場合は、promise のみを使用することもできます

このアプローチにトレードオフがあるかどうかはわかりませんが、コメントでお知らせください。

PSこの回答が気に入ったら、M FuatNUROĞLUの回答にも投票することを忘れないでください:)


0

同様の質問がありました。

以下は、後で別の状態変更者から呼び出されました。したくなかったので。

function foo() {
    // this was called many times which was not needed
    observable.subscribe(func);
    changeObservableState("new value");
}

unsubscribe()以下のようにサブスクライブした後で試してみることにしました。

function foo() {
    // this was called ONE TIME
    observable.subscribe(func).unsubscribe();
    changeObservableState("new value");
}

subscribe(func).unsubscribe();のようsubscribeOnce(func)です。

私もそれがあなたを助けたと思います。

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