JavaScript has a "run to completion" model which means that code in the current event loop block will run until it is completed before processing any messages in the event queue. When you do this:
for (var i = 0; i < len; i++) {
someAsync(() => doSomething(i));
}
You are actually posting len messages to the event queue which will not be executed until the for loop completes. This means that i will already be incremented to the value of len before doSomething(i) gets called. var declares a variable in execution context.
Instead, you can use let which declares a variable in block scope context which means that i keeps its value for each individual block in which it was declared.
That being said, rather than use a for loop I would suggest some different approaches:
- Avoid making http calls like this in a loop. If possible, consolidate it to a single call. This will depend on the API you are using.
- Use
.forEach or .map on the array (this.recentArtists.topartists.artist) in this case.
ex:
this.recentArtists.topartists.artist.forEach(({ mbid }) => {
this.http.get(`${this.apiUrl}?method=artist.getsimilar&mbid=${mbid}`).pipe(
map(res => res.json())
).subscribe();
});
Your use of res => res.json() indicates that you are using the older HttpModule instead of HttpClientModule where that step would be unnecessary. I recommend upgrading.
If you must use all of these API calls at once, I recommend that you use RxJS's forkJoin to wait for all of the requests to complete at once. For example:
forkJoin(...this.recentArtists.topartists.artist.map(({ mbid }) =>
this.http.get(`${this.apiUrl}?method=artist.getsimilar&mbid=${mbid}`).pipe(
map(res => res.json())
))
)).subscribe(console.log);
let i = 0instead ofvar i = 0