1

I have an Ionic app where on one of the page I am inserting some records in SQLite DB after the user fills out a form. In order to make sure that the user navigates to the next page only after the data gets inserted in DB I am using async/await feature.

What I am not sure though is if I am using this feature correctly because my console logs say otherwise.

In my console logs I see the message "******Navigate to Home page" and then "Executed INSERT USER CONTRACT sql..." which baffles me as the navigation statement should be the last one that should be displayed in the console logs.

I have gone through this SO link(Typescript sleep) and some other online articles but not sure if I am missing anything.

Console Logs:

[app-scripts] [23:07:08]  console.log: Looping through the contracts data to store them in DB....
[app-scripts] [23:07:08]  console.log: Into the insertUserContract method........
[app-scripts] [23:07:08]  console.log: cropId: 4
[app-scripts] [23:07:08]  console.log: contract:
[app-scripts]             {"contractName":"C1","contractBushels":"1000","contractPrice":"5","contractFulfillmentDt":"2019-01"}
[app-scripts] [23:07:08]  console.log: ***********Navigating to Home page now.....
[app-scripts] [23:07:08]  console.log: contractDollarAmt: 5000
[app-scripts] [23:07:08]  console.log: ****************Into the home page
[app-scripts] [23:07:08]  console.log: Loading all user crops from DB....
[app-scripts] [23:07:08]  console.log: this.userCropCfgs: undefined
[app-scripts] [23:07:08]  console.log: Executed INSERT USER CONTRACT sql...{"rows":{"length":0},"rowsAffected":1,"insertId":1}
[app-scripts] [23:07:08]  console.log: Executed saveUserCrop sql...{"rows":{"length":0},"rowsAffected":1,"insertId":1}
[app-scripts] [23:07:08]  console.log: rowsAffected: 1
[app-scripts] [23:07:08]  console.log: @@@@@@@result: 1

UserContractPage.ts

addUserContract(val: any) {
    let myUserContract = val as UserContractTxModel;
    let cropId: number = myUserContract.cropId;
    let contractCnt = myUserContract.contracts.length;
    let contracts: ContractTxModel[] = myUserContract.contracts;

    console.log("Looping through the contracts data to store them in DB....");
    (async () => {
      let results: number[] = [];
      for (let i = 0; i < contractCnt; i++) {
        this.userContractProvider.insertUserContract(cropId, contracts[i])
          .then((result) => {
            console.log("@@@@@@@result: " + result);
            results.push(result);
          })
          .catch(e => console.error(JSON.stringify(e)));
      }

      //navigate only when the above code executes and data gets inserted in DB
      await this.navigate();
    })();
  }

  private navigate() {
    console.log("***********Navigating to Home page now.....");
    this.navCtrl.push(HomePage);
  }

UserContractProvider.ts (Actually inserts data in DB)

insertUserContract(cropId: number, contract: ContractTxModel): Promise<number> {
    console.log("Into the insertUserContract method........");
    console.log("cropId: " + cropId);
    console.log("contract: " + JSON.stringify(contract));
    return this.databaseProvider.getDatabase().then(database => {
      let contractDollarAmt = contract.contractBushels * contract.contractPrice;
      console.log("contractDollarAmt: " + contractDollarAmt);
      return database.executeSql(SQL_INSERT_INTO_USER_CONTRACT_TX_TABLE, [
        cropId, contract.contractName,
        contract.contractBushels, contract.contractPrice, contractDollarAmt,
        contract.contractFulfillmentDt
      ])
        .then((data) => {
          console.log("Executed INSERT USER CONTRACT sql..." + JSON.stringify(data));
          console.log("Executed saveUserCrop sql..." + JSON.stringify(data));
          console.log("rowsAffected: " + data.rowsAffected);
          return data.rowsAffected;
        }).catch((e) => {
          console.error("Error: " + JSON.stringify(e));
        });
    });
  }
Nital
  • 4,754
  • 16
  • 75
  • 146

2 Answers2

3

The only thing you're awaiting in the for loop is await this.navigate(); - the other Promises are simply being declared, but not waited for. If you want the loop to only progress once a insertUserContract is finished, put await in front of the call:

for (let i = 0; i < contractCnt; i++) {
  await this.userContractProvider.insertUserContract(cropId, contracts[i])
    .then((result) => {
      console.log("@@@@@@@result: " + result);
      results.push(result);
    })
    .catch(e => console.error(JSON.stringify(e)));
}

//navigate only when the above code executes and data gets inserted in DB
this.navigate();

Also note that navigate isn't asynchronous, so don't await it.

CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
1

Although that might have worked for you, the correct way to do this is to use Promise.all feature which allows you to stack promises and wait for them all to complete before you continue.

in the proposed response, you are running one insert at a time, which might be what you are trying to achieve.

Furthermore, you are using an await with then().catch() which is sort of an overkill.

However, if you want to run your inserts in parallel you can do the following :

async yourFunctionName() {
    const promises = [];
    for (let i = 0; i < contractCnt; i++) {
      promises.push(this.userContractProvider.insertUserContract(cropId, contracts[i]));
    }
    results = await Promise.all(promises);
    // When all the inserts will complete, this navigate() will execute and the 
    //result of each insert is stored in the array results
     this.navigate();
}
Mehdi
  • 1,843
  • 14
  • 21