angular で Observable/http/asyncコールからレスポンスを返す方法

javascript angular asynchronous typescript observable


サーバーにhttpリクエストを送信してデータを取得するオブザーバブルを返すサービスがあります。このデータを使用したいのですが、常に undefined ます。どうしたの?

Service:

@Injectable()
export class EventService {

  constructor(private http: Http) { }

  getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=> res.json())
                .catch((err)=> err)
  }
}

Component:

@Component({...})
export class EventComponent {

  myEvents: any;

  constructor( private es: EventService ) { }

  ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
        });

    console.log(this.myEvents); //This prints undefined!
  }
}




Answer 1 eko


Reason:

undefined の理由は、非同期操作を行っているためです。つまり、 getEventList メソッドを完了するには時間がかかります(主にネットワーク速度に依存します)。

では、httpコールを見てみましょう。

this.es.getEventList()

subscribe を使用して実際にhttp要求を作成(「発火」)した後、応答を待ちます。待機中、javascriptはこのコードの下の行を実行し、同期の割り当て/操作を検出した場合、それらをすぐに実行します。

したがって、 getEventList() にサブスクライブして応答を待った後、

console.log(this.myEvents);

行はすぐに実行されます。そして、その値は、サーバーから(または最初に初期化したものに)応答が届くまでは undefined です。

するのと似ています。

ngOnInit(){
    setTimeout(()=>{
        this.myEvents = response;
    }, 5000);

    console.log(this.myEvents); //This prints undefined!
}


Solution:

では、どうすればこの問題を克服できるでしょうか。 subscribe メソッドであるコールバック関数を使用します。データがサーバーから到着したとき、それは応答を持つ subscribe 内にあるからです。

だからコードを変更して

this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //<-- not undefined anymore
    });

はしばらくするとレスポンスを表示します。


あなたがすべきこと:

単にログに記録する以外にも、応答にはさまざまな処理が必要になる場合があります。データが到着したら、コールバック内( subscribe 関数内)でこれらすべての操作を実行する必要があります。

もう1つ言及する必要があるのは、 Promise のバックグラウンドにいる場合、 then コールバックはオブザーバブルで subscribe することです。


してはいけないこと:

非同期操作を同期操作に変えようとするべきではありません(できるわけではありません)。非同期操作を行う理由の一つは、ユーザーがその時間内に他のことをしている間に操作が完了するのを待たせないようにするためです。非同期操作の一つが完了するのに3分かかるとします。非同期操作がなかった場合、インターフェイスは3分間フリーズしてしまいます。


推奨読書:

この回答の元のクレジットは次のとおりです:非同期呼び出しから応答を返すにはどうすればよいですか?

しかし、Angular2のリリースではtypecriptとobservablesを導入したので、この回答はobservablesを使った非同期リクエストの扱い方の基本をカバーできればと思います。




Answer 2 RAVI PATEL


angularjavascriptのhttpコールは非同期操作です。そのため、httpコールを行う際には、このコールを終了し、別のスレッドで次の行の実行を開始するために新しいスレッドを割り当てます。これが未定義の値を取得している理由です。

this.es.getEventList()  
      .subscribe((response)=>{  
       this.myEvents = response;  
        console.log(this.myEvents); //<-this become synchronous now  
    });



Answer 3 Kliment Ru


あなたは使用することができますasyncPypeをあなたが唯一のテンプレートでmyEventsを使用している場合。

ここにasyncPypeとAngular4 HttpClientの例https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts




Answer 4 Kooldandy


Observables は怠惰なので、値を取得するには subscribe しなければなりません。コードの中で適切にサブスクライブしたのに、同時に出力を 'subscribe' ブロックの外にログに記録してしまいました。これが 'undefined' になっている理由です。

ngOnInit() {
  this.es.getEventList()
    .subscribe((response) => {
        this.myEvents = response;
    });

  console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}

そのため、サブスクライブブロック内でログを記録すれば、レスポンスが適切に記録されます。

ngOnInit(){
  this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //Inside the subscribe block 'http response'
    });
}



Answer 5 Suneet Bansal


ここでの問題は、 subscribe() 。)ブロックの外で console.log() を実行しているときに this.myEvents を非同期ブロックである subscribe() に初期化していることです。つまり、 this.myEvents が初期化される前に console.log() が呼び出されます。

console.log()のコードも subscribe()の中に移動してください。

ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents);
        });
  }