Home > Mobile >  Resolve is returned before for loop is completed inside a Promise
Resolve is returned before for loop is completed inside a Promise

Time:02-01

I am very confused to why the the return resolve({ status: true, data: newIDs }); is called before the for loop has finished.

Code

  createPallet: (data) => {
    return new Promise(async (resolve, reject) => {
      const newIDs = [];
      try {
        for (const record of data) {
          mysqlConnection.beginTransaction();
          mysqlConnection.query(
            "INSERT INTO ...",
            [record.BatchId, record.PalletNumber, record.PrimaryWeightId],
            async (error, results) => {
              if (error) {
                return reject(error);
              }

              // Create pallet sku record
              await PalletSkusService.createPalletSku(
                ...
              );

              console.log(results.insertId);
              newIDs.push(results.insertId);
            }
          );
        }
        return resolve({ status: true, data: newIDs });
      } catch (error) {
        mysqlConnection.rollback();
        return reject(error);
      }
    });
  },

Expectation

I expect the for loop to get all the new inserted id's and store them into newIDs array. Once that is done, I can return a resolve with the data.

However, this part I don't quite understand is - why does the resolve is ran before the for loop has finished?

What is the correct approach in this situation?

CodePudding user response:

mysqlConnection.query is returning immediately and not waiting for the data to return. I don't know what library you're using for this but you want to find the promise based method to accomplish this. Then, modify the loop so it waits for an array of promises to complete before resolving.

  createPallet: (data) => {
    return new Promise(async (resolve, reject) => {
      const newIDs = [];
      try {
        // modified loop
        await Promise.all(data.map((record) => {
          mysqlConnection.beginTransaction();
          // this is a best guess for how the a promise-style query would look
          const await result = await mysqlConnection.query(
            "INSERT INTO ...",
            [record.BatchId, record.PalletNumber, record.PrimaryWeightId]
          );

          // Create pallet sku record
          await PalletSkusService.createPalletSku(
            ...
          );

          console.log(results.insertId);
          newIDs.push(results.insertId);

        }));

        return resolve({ status: true, data: newIDs });
      } catch (error) {
        mysqlConnection.rollback();
        return reject(error);
      }
    });
  },

CodePudding user response:

  1. The async statement in the first line returns another promise, which is not necessary.
  2. You don't need to return anything, instead you must call directly the reject and resolve functions.
  3. You are resolving the promise prematurely, because the loop doesn't wait for asynchronous calls, so it should be better to put the promise inside the loop, and use a Promise.all() function. Note that this function receives an array with the returned values from all the promises when they are resolved.
  4. Consider to replace the try/catch statement by a catch outside of the promise, because the try/catch doesn't catch asynchronous calls.
  createPallet: (data) => {
    const promises = [];
    for (const record of data) {
        promises.push(new Promise((resolve, reject) => {
          mysqlConnection.beginTransaction();
          mysqlConnection.query(
            "INSERT INTO ...",
            [record.BatchId, record.PalletNumber, record.PrimaryWeightId],
            async (error, results) => {
              if (error) {
                reject({mysqlConnection, error});
              }

              // Create pallet sku record
              await PalletSkusService.createPalletSku(
                ...
              );

              console.log(results.insertId);
              resolve(results.insertId);
            }
          );
        }).catch({mysqlConnection, error}) => {
          mysqlConnection.rollback();
          throw new Error(error);
        }))
    }

    return Promise.all(promises).then((newIDs) => {
        return { status: true, data: newIDs };
    })
  },
  • Related