2016-04-05 15 views
2

ゴール:一連の同期HTTPリクエストを作成し、それを1つの観測可能なストリームとして購読できるようにする。Angular2:動的同期HTTPリクエスト

サンプル(機能しない):

let query_arr = ['test1','test2','test3'] 

function make_request(query_arr){ 

    if (query_arr.length){ 

     let payload = JSON.stringify(query_arr[0]); 
     let headers = new Headers(); 

     query_arr.splice(0,1); 

     this.http.post('https://endpoint/post',payload,{headers:headers}) 
      .map((res:Response) => {make_request(query_arr)}) 

    } 

}.subscribe(
    data => console.log('finished http request, moving on to next http request'), 
    err => console.error(err), 
    () => console.log('all http requests have been finished') 
); 

make_request(query_arr) 

目標機能:

  • 各応答が返されたときにすべての応答が
  • を返したとき
  • が知っている必要があります知っている必要があります

答えて

5

flatMap演算子を利用してリクエストを連続して実行する必要があります(順番に1つずつ)。このためには、データ処理チェーンを再帰的に構築する必要があります。ここでのポイントは、以前の観測可能な観測値(以前の要求によって返された観測値)でオペレータを呼び出すことです。

このようにして、要求は前のものが完了するのを待ってから実行されます。すべてのリクエストが実行されたときにサブスクライブするときにコールバックが呼び出されます。ここで

は、このアプローチの実装サンプルです:

makeRequest(queryArr, previousObservable){ 
    if (queryArr.length) { 
    let payload = JSON.stringify(queryArr[0]); 
    let headers = new Headers(); 
    (...) 

    queryArr.splice(0,1); 

    var observable = null; 
    if (previousObservable) { 
     observable = previousObservable.flatMap(() => { 
     return this.http.post('https://testsoapi.apispark.net/v1/entities', payload,{ 
      headers:headers 
      }) 
      .map((res:Response) => res.json()) 
      .do(() => { 
      console.log('request finished'); 
      }); 
     }); 
    } else { 
     observable = this.http.post('https://testsoapi.apispark.net/v1/entities', payload, { 
     headers:headers 
     }) 
     .map((res:Response) => res.json()) 
     .do(() => { 
      console.log('request finished'); 
     }); 
    } 

    return this.makeRequest(queryArr, observable); 
    } else { 
    return previousObservable; 
    } 
} 

このメソッドは、このように最初に呼び出すことができます。https://plnkr.co/edit/adtWwckvhwXJgPDgCurQ?p=preview

test() { 
    let queryArr = [ 
    { val: 'test1' }, 
    { val: 'test2' }, 
    { val: 'test3' } 
    ]; 

    this.makeRequest(queryArr).subscribe(
    () => { 
     console.log('all requests finished'); 
    }); 
} 

このplunkrを参照してください。

1

あなたのコードにも構文上の誤りがいくつかありましたが、それに対処する必要があります。しかし、代わりにconcatMap + deferを使用することで大幅に単純化できます。

let query_arr = ['test1','test2','test3']; 
let self = this; 

Rx.Observable.from(query_arr).map(JSON.stringify) 
    .concatMap(payload => { 
    let headers = new Headers(); 
    return Rx.Observable.defer(() => { 
     self.http.post('https://endpoint/post',payload,{headers:headers}); 
    }); 
    }, resp => resp.json()) 
    .subscribe(
    data => console.log('finished http request, moving on to next http request'), 
    err => console.error(err), 
    () => console.log('all http requests have been finished') 
); 

本の基本的な考え方は、それはそれは熱心に彼らがに加入している場合にのみ実行されます怠惰な一連の要求を作成する観察可能にクエリ配列を変換することです。ただし、deferに投稿をラップすると、各リクエストは前のリクエストが完了したときにのみディスパッチされます。

0

それとも、配列を与えるtypescriptですにおける非再帰バージョンは

リターンで

observableObj(res.jsonを())、それがサブスクライブにhttpcall

から戻ったときには、各応答を知るforkjoinします返されたすべての応答と値の配列を知っています

const observableObj = (obj) => Observable.of(obj) 

class Requests { 

private query_arr = ['test1','test2','test3'] 
private url = 'https://testsoapi.apispark.net/v1/entities' 

public make() { 
    this.processHttp().subscribe(
     (d) => { 
      console.log(d)    
     }, 
     (e) => { 
      console.log(e) 
     }, 
     () => { 
      console.log("http calls are done") 
     }) 

} 

private httpCall(options : RequestOptions) : Observable<Response> { 
    let username : string = 'xxx' 
    let password : string = 'yyy' 
    let headers = new Headers() 
    headers.append("Authorization", "Basic " + btoa(username + ":" + password)) 
    headers.append("Content-Type", "application/x-www-form-urlencoded") 
    options.headers = headers 
    return this.http.get(this.url,options) 
} 

private createRequestOptions(option1 : string) { 
    let data = {'option1':option1} 
    let params = new URLSearchParams() 
    for(var key in data) { 
    params.set(key, data[key]) 
    } 
    let options = new RequestOptions({ 
    search: params 
    }) 
    return options 
} 

private processHttp() { 
    return Observable.forkJoin(
     this.query_arr.map(option => { 
      return this.httpCall(createRequestOption(option)).flatMap((res: Response) => { 
       return observableObj(res.json()) 
      }) 
     }))    
} 
}