Vladimir Despotovic
Vladimir Despotovic

Reputation: 3498

Angular await not waiting

I have a bit of code with await-s set like this:

async calculateDeletionResidualsData(res) {
    //console.log("resss is:");
    //console.log(res);

    let selectedCountries = this.countriesList.filter(c => c.selected);
    let selectedIndicators = this.indicatorsList.filter(i => i.selected);

    await selectedCountries.forEach(async c => {
        // taking each (selected) country

        await selectedIndicators.forEach(async i => {
            // taking each (selected) indicator

            // Form the series for the calculation of residuals
            let series = [];
            deletionResidualsRelevantYears.forEach(y => {
                series.push(res[c.label][y][i.label][0]);
            });
            // Calculate deletion residuals
            let drr = await util.calculateDeletionResidualsStatistics(
                deletionResidualsRelevantYears.length,
                series,
                this.deletionResidualsService
            );

            this.drr[c.label][i.label] = drr;
        });
    });

    console.log("setting qrReady to true");
    this.qrReady = true;
}

I can clearly see that the calls to the util.calculateDeletionResidualsStatistics are still being made in the network tab of my browser, but I also see that the console.log("setting qrReady to true"); has already been fired, and it shouldn't be fired. Why are all these awaits skipped and jumped over to the last line of code?

Upvotes: 2

Views: 1216

Answers (3)

Reactgular
Reactgular

Reputation: 54741

You need to use Promise.all() with await if you have a collection of promises, and use a map() operation to create an array of promises.

    await Promise.all(selectedCountries.map(async c => {
        await Promise.all(selectedIndicators.map(async i => {
            let drr = await util.calculateDeletionResidualsStatistics(...);
            // ...
        });
    });

    console.log('printed after everything is finished');

Keep in mind that Promise.all() will resolve an array of results after all of the inner promises have resolved. The order of those promises is unpredictable as they resolve in parallel.

You will end up with nested Promise.all() that will resolve in batches before the top level Promise.all() resolves.

Since it looks like you are discarding the results of the outer promises, then I don't see a real issue here with the order. You just want to run some code after everything is done.

Upvotes: 1

igg
igg

Reputation: 2250

await only works on functions that return a Promise. forEach does not. Assuming util.calculateDeletionResidualsStatistics returns a Promise, write your code like this instead:

calculateDeletionResidualsData(res) {
    //console.log("resss is:");
    //console.log(res);

    let selectedCountries = this.countriesList.filter(c => c.selected);
    let selectedIndicators = this.indicatorsList.filter(i => i.selected);

    selectedCountries.forEach( c => {
        // taking each (selected) country

        selectedIndicators.forEach(async i => {
            // taking each (selected) indicator

            // Form the series for the calculation of residuals
            let series = [];
            deletionResidualsRelevantYears.forEach(y => {
                series.push(res[c.label][y][i.label][0]);
            });
            // Calculate deletion residuals
            let drr = await util.calculateDeletionResidualsStatistics(
                deletionResidualsRelevantYears.length,
                series,
                this.deletionResidualsService
            );
            this.drr[c.label][i.label] = drr;
        });
    });

    console.log("setting qrReady to true");
    this.qrReady = true;
}

If not, please edit your post and I'll try to provide a different solution.

Upvotes: 1

Akshay Bande
Akshay Bande

Reputation: 2587

await won't work for loops that use callbacks. Don’t ever use await with forEach. Use a for-loop (or any loop without a callback) instead

forEach is not promise-aware. It cannot support async and await. You cannot use await in forEach.

Learn more...

Upvotes: 4

Related Questions