Home > Enterprise >  Typescript - subscription inside iteration
Typescript - subscription inside iteration

Time:09-22

I am trying to call the "getData" API over and over for each value in the "myArray" variable. Each time it gets new data from the "getData" call, I am trying to push the result to an array so I can manipulate the values in the "destinationArray" section of code. However, since typescript is not async, it gets to the "destinationArray" code before it's finished in the .subscribe / before it's finished iterating.

I've already tried fixing this with await waitUntil(() => done==true, { timeout: 10015 }); but I keep getting randomly appearing messages in the console saying ERROR Error: Uncaught (in promise): Error: Timed out after waiting for 10015 ms. The naive answer is to just increase the timeout to infinity, but the actual API call itself does not take 10 seconds, it takes about 1 second (if even that long). How can I make it wait until it's finished iterating / subscribing before it moves onto the "destionationArray" section at the bottom, without seeing that timeout error message in the console?

let dataFromAPIcall: any[] = []
let myArray: any[] = ["hello","world"]
for(let i = 0; i< myArray.length; i  ) {    
    this.GetDataSubScription = this.myService.getData(myArray[i]).pipe( takeUntil(this.ngUnsubscribe) ).subscribe(data => {
        dataFromAPIcall.push(data)
        if(i 1 == myArray.length) {
            done = true
        }
    });
}

await waitUntil(() => done==true, { timeout: 10015 });
                    
let destinationArray: any[] = [];
for(let i = 0; i < dataFromAPIcall.length; i  ) {
    destinationArray[i] = [dataFromAPIcall[i].something1, dataFromAPIcall[i].something2]
}

CodePudding user response:

You can zip your api calls and handle all responses in a reactive way, without using imperative state variables:

After all observables emit, emit values as an array

// creating an array of observables. The requests are not fired yet.
const requests = myArray.map(i => this.myService.getData(i));
const destinationArray: any[] = [];

// passing the request array to the zip function.
// this will actual initiate the requests and emit when ALL
// requests are done
zip(...requests).pipe(
  tap(responses => {
      // maping responses to destinationArray
      destinationArray = responses.map(dataFromAPIcall => [dataFromAPIcall.something1, dataFromAPIcall.something2])
  }),
  tap(_ => {
    // continue here
  })
).subscribe();
  • Related