Home > Software engineering >  Use async await with Array.map not working
Use async await with Array.map not working

Time:10-13

I've used this approach, it should give me the Expected Output which I've mentioned below. But, due to asynchronous execution, it is giving the Actual Output. So, Please help me to solve the same.

See, I'm calling one async function, inside i'm running three nested map loops. And in the third loop I'm connecting the database and fetching values. Based on the value, I'm generating the values of the Object which is empty at the first. And once the function called, it is triggering the then method.That's where the problem arises, I need that then function to be executed after the called function executed completely. This is the complete problem statement

Given the following code:

 let messageObject = {};
 async function storeManager() {
  // storing the defects or modifying
  console.log('hii from storeManager()');
  await Promise.all(
    Object.keys(filledDefects).map((defectName) => {
      Object.keys(filledDefects[defectName]).map((subDefectName) => {
        Object.keys(filledDefects[defectName][subDefectName]).map(
          async (zone) => {
            const result = await dbConnectedPool.query(
              `SELECT * FROM defect_table WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone = ${zone.replace(
                '_',
                ''
              )}`
            );

            if (result.rows.length == 0) {
              // block to save defects record for the first time
              console.log(
                `INSERT INTO defect_table (body_number,mode,category,subcategory,defect,subdefect,zone,defectCount,date,time,username) VALUES (${enteredBodyNumber},'${mode}','${selectedCategory}','${selectedSubCategory}','${defectName}','${subDefectName}',${zone.replace(
                  '_',
                  ''
                )},${
                  filledDefects[defectName][subDefectName][zone]
                },'${date}','${time}','${username}');`
              );
              await dbConnectedPool.query(
                `INSERT INTO defect_table (body_number,mode,category,subcategory,defect,subdefect,zone,defectCount,date,time,username) VALUES (${enteredBodyNumber},'${mode}','${selectedCategory}','${selectedSubCategory}','${defectName}','${subDefectName}',${zone.replace(
                  '_',
                  ''
                )},${
                  filledDefects[defectName][subDefectName][zone]
                },'${date}','${time}','${username}');`
              );

              mod.set(
                messageObject,
                `Newly Saved Zone.${zone}.${defectName}.${subDefectName}`,
                filledDefects[defectName][subDefectName][zone]
              );
              console.log('inside: ', messageObject);
            } else {
              // block to modify existing defect records

              console.log(
                `UPDATE defect_table SET defectCount=${
                  filledDefects[defectName][subDefectName][zone]
                },date='${date}',time='${time}',username='${username}' WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone=${zone.replace(
                  '_',
                  ''
                )}`
              );

              await dbConnectedPool.query(
                `UPDATE defect_table SET defectCount=${
                  filledDefects[defectName][subDefectName][zone]
                },date='${date}',time='${time}',username='${username}' WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone=${zone.replace(
                  '_',
                  ''
                )}`
              );

              mod.set(
                messageObject,
                `Overwritten Zone.${zone}.${defectName}.${subDefectName}`,
                filledDefects[defectName][subDefectName][zone]
              );
              console.log('inside: ', messageObject);
            }
            // checking whether already record exists with same aspects
          }
        );
      });
    })
  );
  console.log('bye from storeManager()');
}

storeManager().then(() => {
  console.log('message outside:', messageObject);
});

Expected Output:

hii from storeManager()
bye from storeManager()
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=210
inside:  { 'Overwritten Zone': { _210: { Surface: [Object] } } }
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=215
inside:  {
  'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}
message outside: {
  'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}

Actuall Output:

hii from storeManager()
bye from storeManager()
message outside: {}
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=210
inside:  { 'Overwritten Zone': { _210: { Surface: [Object] } } }
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=215
inside:  {
  'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}

CodePudding user response:

Promise.all expects an array of promises as argument, but you pass it an array of undefined values instead. That means Promise.all will return a promise that is resolved immediately.

Two causes for this problem:

  • the outer map callbacks don't have a return statement (so they map each defectName and each subDefectName to undefined)
  • If you would return the result of the inner .map calls, then each defectName maps to an array (of arrays ...), which still isn't what you need. You don't want a nested array, but a flat array, so use return Object.keys().flatMap instead of Object.keys().map

CodePudding user response:

You'll need to use Promise.all everywhere you are producing an array of promises, not just on the outermost call. And you'll need to make the map callbacks actually return those promises!

await Promise.all(Object.entries(filledDefects).map(async ([defectName, defect]) => {
  await Promise.all(Object.entries(defect).map(async ([subDefectName, subDefect]) => {
    await Promis.all(Object.entries(subDefect).map(async ([zoneName, zone]) => {
      await …;
    }));
  }));
}));

Alternatively you can also write this without some of the async/await:

await Promise.all(Object.entries(filledDefects).map(([defectName, defect]) =>
  Promise.all(Object.entries(defect).map(async ([subDefectName, subDefect]) =>
    Promis.all(Object.entries(subDefect).map(async ([zoneName, zone]) => {
      await …;
    }));
  ));
));
  • Related