Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.9k views
in Technique[技术] by (71.8m points)

angular - Observable Continue calling API and changing parameters based on condition

I've read the Rx.js repeat Documentation in an effort to find out how I can continue calling an api based upon the response that I receive from the API. I'm calling an API that can only send back 2k records at a time. The API will send back a value for me to send it so that I can continue receiving the records until they return a done value.

So the flow goes as follows:

  1. Make a GET request a query parameter reqMode='':
  2. retrieve response with the last array containing reqMode with a value or done.
  3. If I receive a value then I need to make the same request but send the reqMode parameter with the value.
  4. If i receive done then I'll stop and return all of the records since the first call.

I get the first set of values when subscribing normally, but this would be my attempt after reading the docs, but it doesn't make sense:

getRecords(){
    let url = this.url + 'reqMode=';
    return this.http.get(url)
            .doWhile() //What would I do here
}

When trying to do .doWhile with a Observable that is type Observable<response>. I'm looking for any alternative using Observables for what I need to do.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't think repeat() is a good operator for this. If I understand you correctly you want to repeat the HTTP request based on the response of the previous request. Operator repeat() is good if you wanted to repeat the same request multiple times.

I'd use concatMap() and recursively call itself until the reqMode is eqaul to "done":

See live demo: http://plnkr.co/edit/w0DdepslTaKrLSB3aIkA

import {Observable, Subject} from 'rxjs';

const result = new Subject();
const closeBuffer = new Subject();
const buffer = result.buffer(closeBuffer.asObservable());

function sendHttpRequest(reqMode) {
  return Observable.of('{"reqMode":' + reqMode + '}')
    .map(response => JSON.parse(response))
    .concatMap(data => {
      console.log('HTTP Response:', data);
      // Add data to the buffer of results
      result.next(data);

      if (data.reqMode == 'done') {
        // Return an empty value wrapped as an Observable so concatMap can work
        // with it and emit onNext when it completes (which is immediately
        // thanks to the `.of()` operator).
        return Observable.of(null);
      } else {
        // Simulate that the next call returns 'done'
        return sendHttpRequest('"done"');

        // Uncomment this for real usage
        //return sendHttpRequest(data.reqMode);
      }
    });
}

// Subscribe to the buffer where I'll receive the value.
buffer.subscribe(val => console.log('Next: ', val));

// Simulate HTTP request with reqMode = 42
sendHttpRequest(42).subscribe(() => {
  console.log('done');
  // Emit values from the buffer.
  closeBuffer.next(null);
  closeBuffer.complete();
});

I use of() operator to simulate a request and to return a value wrapped as an Observable. I also use Subject to hold all responses that are buffered using buffer() operator. The I subscribe to the buffer to get the final array of responses (If you wrap this code into a function you'll most likely return the buffer where you can subscribe later).

The response is following:

HTTP Response: Object {reqMode: 42}
HTTP Response: Object {reqMode: "done"}
Next:  [Object, Object]

See similar question: Angular 2 + rxjs - how return stream of objects fetched with several subsequent http requests


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...