内部にObservableサブスクリプションがある関数から値を返す方法は?


96

Observableが存在する関数から返される値をObservableから抽出する方法がわかりません。返される値だけが必要です。それ以外は必要ありません。

動作する現在のバージョン

function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            console.log(data)
        }
    )
}
getValueFromObservable()

これが機能し、値を返す関数が必要です:

function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            return data
        }
    )
}
console.log(getValueFromObservable())

ここで何が悪いのですか?


2
Observable / Promiseを返して、Observableが解決されたときにデータを渡す必要があります
galvan

2
このための簡単なコードを記述できますか?
テディ

6
あなたが達成しようとしているのはアンチパターンです:あなたは非同期タスクを「同期」しようとしています。これは、オブザーバブルが機能するはずの方法ではありません。つまり、ほとんどの場合、オブザーバブルを入力として持つ関数は、オブザーバブルを返すか、何も返さないはずです。そして、あなたが出力で何かをする必要があるとき、それを購読してください。この場合、データをconsole.logしたい場合は、内部で実行してくださいsubscribe
Can Nguyen

1
あなたが言ったすべてを理解しました 私はコンソールログをデモとして使用していますが、そのデータをさらに使用します。そのため、オブザーバブルの外部でコンソールログを使用する必要があります。ポイントは、オブザーバブルをサブスクライブし、データを取得し、サブスクライブを解除してデータを返すことができる関数をその関数で持つことです。これにより、そのデータをさらに使用できます。アンチパターンであることはわかっていますが、機能させるにはそれが必要です。どんな助けでもありがたいです。現在私の解決策は機能していますが、私はそれについてあまり自信がありません。
テディ

4
ご注目下さい!セクション「解決策」のコードは完全に正しくありません。使わないで!セクションthis.store.subscribe((data:any)=> {output = data}).unsubscribe()が戻るまで終了する場合にのみ機能します。それ以外の場合はundefinedを返します。
Rodion Golovushkin

回答:


56

編集:RXJSの最新バージョンでのパイプの動作方法に加えられた変更を反映するためにコードを更新しました。すべての演算子(私の例では)がpipe()演算子にラップされています。

この質問はかなり前のことで、きっと今では適切な解決策があるはずですが、これを探している人は非同期パターンを維持するためにPromiseで解決することをお勧めします。

より詳細なバージョンでは、新しいPromiseを作成します。

function getValueFromObservable() {
    return new Promise(resolve=>{
        this.store.pipe(
           take(1) //useful if you need the data once and don't want to manually cancel the subscription again
         )
         .subscribe(
            (data:any) => {
                console.log(data);
                resolve(data);
         })
    })
}

受信側では、次のようなもので解決するという約束を「待つ」必要があります。

getValueFromObservable()
   .then((data:any)=>{
   //... continue with anything depending on "data" after the Promise has resolved
})

よりスリムなソリューションは、代わりにRxJSの.toPromise()を使用することです。

function getValueFromObservable() {
    return this.store.pipe(take(1))
       .toPromise()   
}

もちろん、受信側は上記と同じです。


getValueFromObservable関数の戻り値の型は何ですか?
hardywang 2018

ストアデータのタイプを問わず、promiseである必要があります。例:Promise <StoreType>
jparg 2018年

4
あなたはまだ解決する必要のあるpromiseを返し、値を直接返していません。
Roj

1
プロパティ 'take'はタイプ 'Observable <>'に存在しません
Memmo

1
@Memmoは代わりに.pipe(take(1))を試してください
Thibault

20

これは使用の正確なアイデアではありません Observable

コンポーネントでは、オブジェクト(コンポーネントで使用するもの)を保持するクラスメンバーを宣言する必要があります

export class MyComponent {
  name: string = "";
}

次に、Serviceが返されますObservable

getValueFromObservable():Observable<string> {
    return this.store.map(res => res.json());
}

Component それから値を取得できるように自分自身を準備する必要があります。

OnInit(){
  this.yourServiceName.getValueFromObservable()
    .subscribe(res => this.name = res.name)
}

から値をObservable変数に割り当てる必要があります:

そして、あなたのテンプレートは変数を消費しますname

<div> {{ name }} </div>

使用の別の方法Observableは、asyncパイプhttp://briantroncone.com/?p=623

:質問の内容と異なる場合は、質問を詳細に更新してください


まあ、そうではありません。問題は、データがオブザーバブル内にキャプチャされ、コンソールログに記録できることです。私はその値とconsole.logまたはそれが存在する関数を呼び出すことによって別のファイルから何でも返したいです。
テディ

Andreiはname、コンポーネントのname変数に割り当てることにより、コールバックの外部で利用できるようにする方法を指摘しました。nameあなたの場合、同期して戻ることはできません。
Matt

@マット:Oninitそのようには使用できません。明示的に返す必要がある場合、呼び出しコードは次のようになります this.actions$.ofType(SearchActions.SEARCH_MULTIPLE_NEW_QUERY).map(toPayload).fnWithMultipleAsyncReturns()
ishandutta2007

@ ishandutta2007こんにちは。あなたの問題に関して、SOで新しい質問を作成する方がよいでしょう。
マット

@Matt:ケースには、あなたが見てみたい、作成した(stackoverflow.com/questions/43381922/...
ishandutta2007

7

返される同じObservableを事前サブスクライブする場合は、次を使用します。

。行う():

function getValueFromObservable() {
    return this.store.do(
        (data:any) => {
            console.log("Line 1: " +data);
        }
    );
}

getValueFromObservable().subscribe(
        (data:any) => {
            console.log("Line 2: " +data)
        }
    );

3
.map(data => data)同じことを行うような他の演算子を使用して、結果を期待する場所にサブスクライブすることもできます
ashok_khuman

ashok_khumanに同意します。これがガイドangular.io/guide/pipesです
アルマンドペレア

これは良い答えかもしれませんが、実際にはそれについて何も説明しなかったので、悪い答えになります。「事前購読」とはどういう意味ですか?そしてそれはスレッドオープナーからの質問を解決するべきですか?
Florian Leitgeb 2018

RxJSでは6 doが呼び出さtapれ、パイプで使用する必要があることに注意してください。また、そのノートtapのようなさまざまなハンドラの複数のパラメータを取りnextcompleteそしてerror
Simon_Weaver

6

問題は、データがオブザーバブル内にキャプチャされ、コンソールログに記録できることです。私はその値とconsole.logまたはそれが存在する関数を呼び出すことによって別のファイルから何でも返したいです。

オブザーバブル内で「現在の値」のゲッターを探しているように見えます。

SubjectObservableそんなことはありません。値が発行されると、その値はサブスクライバーに渡さObservableれ、で処理されます。

を使用しBehaviorSubjectて、最後に発行された値を保存し、新しいサブスクライバーにすぐに発行できます。

getValue()現在の値を取得するメソッドもあります。

参考文献:

RxJS BehaviorSubject

RxJS SubjectまたはObservableの現在の値を取得するにはどうすればよいですか?


2

観測可能な値は、任意の場所から取得できます。ソースシーケンスは、最初に、他の場所に放出できる特別なオブザーバーにプッシュされます。これは、Reactive Extensions(RxJS)のSubjectクラスで実現されます。

var subject = new Rx.AsyncSubject();  // store-last-value method

オブザーバに値を格納します。

subject.next(value); // store value
subject.complete(); // publish only when sequence is completed

他の場所から値を取得するには、次のようにオブザーバーをサブスクライブします。

subject.subscribe({
  next: (response) => {
      //do stuff. The property name "response" references the value
  }
});

対象は観測可能なものと観測者の両方です。他の使用シナリオには、BehaviourSubjectやReplaySubjectなどの他のサブジェクトタイプがあります。

RxJSをインポートすることを忘れないでください。

var Rx = require('rxjs');

1

以前の答えはうまくいくかもしれませんが、オブザーバブルを引き続き使用したい場合は、BehaviorSubjectを使用するのが正しい方法だと思います。

例:

    this.store.subscribe(
        (data:any) => {
            myService.myBehaviorSubject.next(data)
        }
    )

サービス内:

let myBehaviorSubject = new BehaviorSubjet(value);

component.ts内:

this.myService.myBehaviorSubject.subscribe(data => this.myData = data)

これが役に立てば幸いです!


0

たとえば、これは私のhtmlテンプレートです。

<select class="custom-select d-block w-100" id="genre" name="genre"
                  [(ngModel)]="film.genre"
                  #genreInput="ngModel"
                  required>
            <option value="">Choose...</option>
            <option *ngFor="let genre of genres;" [value]="genre.value">{{genre.name}}</option>
          </select>

これは私のコンポーネントのテンプレートにバインドされたフィールドです:

  // Genres of films like action or drama that will populate dropdown list.
  genres: Genre[];

サーバーから映画のジャンルを動的にフェッチします。作成したサーバーと通信するためFilmService

これはサーバーと通信する方法です:

 fetchGenres(): Observable<Genre[]> {
    return this.client.get(WebUtils.RESOURCE_HOST_API + 'film' + '/genre') as Observable<Genre[]>;
  }

なぜこのメソッドはObservable<Genre[]>次のようなものを返さないのGenre[]ですか?

JavaScriptはasync、高価なプロセスの後でメソッドが値を返すまで待機しません。高価なとは、値を返すのに時間がかかるプロセスを意味します。サーバーからデータをフェッチするように。したがって、Observableの参照返してサブスクライブする必要があります。

たとえば私のコンポーネント:

ngOnInit() {
    this.filmService.fetchGenres().subscribe(
      val => this.genres = val
    );
  }

0
function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            return data
        }
    )
}
console.log(getValueFromObservable())

上記の場合、console.logはpromiseが解決される前に実行されるため、値は表示されません。次のように変更してください。

function getValueFromObservable() {
    return this.store
}

getValueFromObservable()
 .subscribe((data: any) => {
    // do something here with data
    console.log(data);
});

他の解決策は、getValueFromObservable内のデータを使用して、演算子のオブザーバブルを返し、関数にサブスクライブする必要がある場合です。

 function getValueFromObservable() {
        return this.store.subscribe((data: any) => {
            // do something with data here
            console.log(data);
            //return again observable.
            return of(data);
       })
    }

    getValueFromObservable()
     .subscribe((data: any) => {
        // do something here with data
        console.log(data);
    });

0

シングルスレッド、非同期、約束志向、反応性傾向のJavaScriptの世界でasync/awaitは、命令型プログラマーの親友です。

(async()=>{

    const store = of("someValue");
    function getValueFromObservable () {
        return store.toPromise();
    }
    console.log(await getValueFromObservable())

})();

そして場合storeは複数の値のシーケンスです:

  const aiFrom = require('ix/asynciterable').from;
  (async function() {

     const store = from(["someValue","someOtherValue"]);
     function getValuesFromObservable () {
        return aiFrom(store);
     }
     for await (let num of getValuesFromObservable()) {
       console.log(num);
     }
  })();

0

適切な方法は、オブザーバブルを関数から返し、必要に応じてサブスクライブすることです。オブザーバブルは遅延しているため、サブスクライブしたときにのみ値の出力を開始します。

ここに、私が最初に遊んでいた、興味深いイベント駆動型ソリューションがもう1つあります。次の例では、nodejsの「events」モジュールを使用してこれを行っています。同様のモジュールが存在する他のフレームワークで使用できます:構文とスタイルは、使用するモジュールによって異なる場合があります)。

var from =require("rxjs").from;
var map = require("rxjs/operators").map;
var EventEmitter = require("events");

function process(event) {
    from([1,2,3]).pipe(
        map(val => `The number is:: ${val}`)
    ).subscribe((data) => {
       event.emit("Event1", data); //emit value received in subscribe to the "Event1" listener
    });
}

function main() {
   class Emitter extends EventEmitter{};
    var event = new Emitter(); //creating an event
    event.on("Event1", (data)=>{ //listening to the event of name "Event1" and callback to log returned result
        console.log(data); //here log, print, play with the data you receive
    });
    process(event); //pass the event to the function which returns observable.
}

main(); //invoke main function

これは、さまざまな場所からデータを放出および聴取する方法でデータを渡すことができるというアイデアを示すための単なる例です。これは、イベント駆動型コードとも呼ばれます。

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