rxjs Observable - subscribe to result in loop and break on condition / cannot read property 'subscribe' of undefined

南楼画角 提交于 2021-02-08 07:58:26

问题


I am new to rxjs and can't seem to find the correct operator for what I am trying to do.

In my example, I have an array I need to populate with results from an another observable, and once I have enough results in that array from making subscribe calls, I want to break and return the array.

// for reference, there is a class variable called keys

    result = getResults(data, index).subscribe((result: any[]) => { 
          doSomethingWith(result);
    });

    getResults(data: any[], index: number) : Observable<any[]> {
       obsFunctionThatGetsMeData(keys[index]).subscribe(result => 

         data = data.concat(result);

          if(data.length >= NEEDED_NUM_DATA) {
              return Observable.of(data);

          } else {

            /* need to call obsFunctionThatGetsMeData(keys[index++]) and do the same logic as above. */

          }
       );
    }

I know it is bad practice to put a subscribe in a subscribe, this is just the idea of what I'm looking for. I know takeWhile works on a condition, but I don't see how I can make extra calls if that condition fails. Does anyone know what operator is best for this kind of behavior?

Thanks!

  • obsFunctionThatGetsMeData returns Observable

Solved my own question Using recursion & switchmap

getResults(data: any[], index: number): Observable<any> {
   return obsFunctionThatGetsMeData(keys[index]).pipe(
        switchMap(result => {
            if (result) {
                data= data.concat(result);

                if (data.length < NEEDED_NUM_DATA && index < keys.length) {
                    return getResults(data, ++index);
                } else {
                    return Observable.of(data);
                }
            }
        }));
}

回答1:


I'm not an expert in RxJS, but I think something like this should be possible:

Rx.Observable.from(obsFunctionThatGetsMeData)
  .take(NEEDED_NUM_DATA)
  .subscribe(doSomethingWith);

public take(count: number): Observable Emits only the first count values emitted by the source Observable.

It's just an ideat to think about and doesn't pretend to be a working solution.




回答2:


Looks like obsFunctionThatGetsMeData emits once (like an HTTP request), and you want to collect results from NEEDED_NUM_DATA number of these requests into array. And also it should append to whatever you already have in data parameter?

Try this:

getResults( data: any[], index: number ): Observable<any[]>
{
    return Observable.range( index, NEEDED_NUM_DATA )
        .concatMap( i => obsFunctionThatGetsMeData( keys[i] ) )
        .reduce(( acc: any[], value ) => acc.concat( value ), data );
}



回答3:


Promises are your friend here. (because you are working with single values).

Although you think you are working with a stream of results (the observables), you are actually just working with a single value at a time. Each value is independently operated on in a loop that pushes the result into an array. So NEEDED_NUM_DATA independent variables consolidated into a a collection.

This code is much easier to rationalize about and to realize your goal:

var NEEDED_NUM_DATA = 4;
var collection = [];
async function getResults() {
  let url = 'https://jsonplaceholder.typicode.com/posts/';
  let i = 1;
  while(collection.length <= NEEDED_NUM_DATA) {
    let result = await getsMeData(url + i++);
    collection.push(result);
  }
}
async function getsMeData(url) {
  const response = await fetch(url);
  const json = await response.json();
  return json;
}
getResults()
.then(()=>console.log(collection));


来源:https://stackoverflow.com/questions/49926634/rxjs-observable-subscribe-to-result-in-loop-and-break-on-condition-cannot-re

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!