Not sure how to populate an array within a method that has Promises within it

Tags: , , , ,



I have a method that performs some basic mathematical calculations in my Ionic app after fetching data from SQLite DB. I want to show these results on a page but the problem is that I am not sure how to put all these calculated values in an object array.

I tried following but the editor is complaining about not resolving promises. To me it looks like I already resolved them by extracting a numeric value from each and assigning them to local variables such as grossMarketable, aphMarketable, amountSold and totalContractDollarAmount.

home.ts

private calculate() {
    console.log("**********Starting calculations now.....");
    let calculations: CalcModel[] = [];
    for (let i = 0; i < this.userCropTxModels.length; i++) {
      let userCropTxModel = this.userCropTxModels[i];
      console.log("userCropTxModel: " + userCropTxModel);

      let grossMarketable = this.userCropProvider.getGrossMarketableByCropId(userCropTxModel.cropId)
        .then(grossMarketable => {
          console.log("grossMarketable: " + grossMarketable);
          return grossMarketable;
        })
        .catch((e) => console.error(JSON.stringify(e)));

      let aphMarketable = this.userCropProvider.getAPHMarketableByCropId(userCropTxModel.cropId)
        .then(aphMarketable => {
          console.log("aphMarketable: " + aphMarketable);
        })
        .catch((e) => console.error(JSON.stringify(e)));

      let amountSold = this.userContractProvider.getTotalContractedBushelsByCropId(userCropTxModel.cropId)
        .then(amountSold => {
          console.log("amountSold: " + amountSold);
        })
        .catch((e) => console.error(JSON.stringify(e)));

      let totalContractDollarAmount = this.userContractProvider.getTotalContractDollarAmountByCropId(userCropTxModel.cropId)
        .then(totalContractDollarAmount => {
          console.log("totalContractDollarAmount: " + totalContractDollarAmount);
        })
        .catch((e) => console.error(JSON.stringify(e)));

      console.log("grossMarketable: " + grossMarketable);
      console.log("aphMarketable: " + aphMarketable);
      console.log("amountSold: " + amountSold);
      console.log("totalContractDollarAmount: " + totalContractDollarAmount);

      /**************************************************
      //THE EDITOR IS SHOWING RED MARKS BELOW
      ***********************************************/
      calculations.push({
        cropName: 'Corn',
        grossMarketable: grossMarketable,
        grossMarketable: grossMarketable,
        amountSold: amountSold,
        totalContractDollarAmount: totalContractDollarAmount
      });
    }
    console.log("calculations: " + calculations);
  }

user-crop.ts (code snippet of UserCropProvider)

getGrossMarketableByCropId(cropId: number): Promise<number> {
    return this.databaseProvider.getDatabase().then(database => {
      return database.executeSql(SQL_SELECT_GROSS_MARKETABLE_BY_CROP_ID, [cropId])
        .then((data) => {
          let grossMarketable: number = 0;
          for (let i = 0; i < data.rows.length; i++) {
            grossMarketable = data.rows.item(i).GROSS_MARKETABLE
          }
          return grossMarketable;
        });
    });
  }

CalcModel.ts

export interface CalcModel {
  cropName: string;
  grossMarketable: number; 
  aphMarketable: number; 
  amountSold: number; 
  totalContractDollarAmount: number; 
}

Answer

Create a promise.all for each user crop model, with inside the list of promises of your async requests.

When you resolve the inner ones, get back a single calculation object. When you resolve all of them, get your calculations list:

Your code should look something like:

private calculate() {
    const promises: Promise<any>[] = []; 
    for (let i = 0; i < this.userCropTxModels.length; i++) {
      let userCropTxModel = this.userCropTxModels[i];
      promises.push(Promise.all([
        this.userCropProvider.getGrossMarketableByCropId(userCropTxModel.cropId),
        this.userCropProvider.getAPHMarketableByCropId(userCropTxModel.cropId),
this.userContractProvider.getTotalContractedBushelsByCropId(userCropTxModel.cropId),
this.userContractProvider.getTotalContractDollarAmountByCropId(userCropTxModel.cropId)
      ]).then(data => ({ 
        cropName: 'Corn',
        grossMarketable: data[0],
        amountSold: data[1],
        totalContractDollarAmount: data[2]
      })));
    }
    Promise.all(promises).then(calculations => console.log(calculations));
  }

EDIT

A bit of refactor. I don’t know if it works, I am just coding without even trying, but just a bit cleaner:

private calculate() {
  const promises: Promise<any>[] = this.userCropTxModels.map(userCropModel => Promise.all([
    this.userCropProvider.getGrossMarketableByCropId(userCropModel.cropId),  
    this.userCropProvider.getAPHMarketableByCropId(userCropModel.cropId),
    this.userContractProvider.getTotalContractedBushelsByCropId(userCropModel.cropId),
    this.userContractProvider.getTotalContractDollarAmountByCropId(userCropModel.cropId)
  ]).then(data => ({
    cropName: 'Corn',
    grossMarketable: data[0],
    amountSold: data[1],
    totalContractDollarAmount: data[2]
  })));
  Promise.all(promises).then(calculations => console.log(calculations));
}

You can even use async/await if you want to write sync/style code



Source: stackoverflow