0

I would like to wait untill my function checkNumber() finish and returns result. Unfortunelly for-off loop doesn't wait for function and do all iterations at start. I tried many combinations with async/await but none of them really worked. When i run this function it prints out as many console.log("start error") as loops, and then I get productList. I would like to stop for loop when checkNumber() returns error.

Main function:

  if (!req.body) {
    res.status(400).send({
      message: "Values can not be empty!"
    });
  }

  console.log("list of products: ", req.body.product);
  const productArr = req.body.product; //array of products retrieved from json
  let productList = [];
  let quantityList = [];
  let error = 0;
  for (const product of productArr) { //iterate through products

    console.log("start error: ", error); // <---- 
    if (error == 1) {
      console.log("stop");
      break;
    }

    //check if product's vat exists in vat table, if not add new
    Vat.checkNumber(product.vat, async function (err, data) {
      console.log("result: ", data);
      if (!data) {
        console.log("not found");
        console.log(err);
        error = 1;
      } else {
        console.log("found");
        const vat_id = data;

        //crete new product obj json
        let newProduct = {
          vat_id: vat_id,
          name: product.name,
          price: product.price
        };

        //store product list and their quantity to use later in sql query
        productList.push(newProduct);
        quantityList.push(product.quantity);
        console.log(productList);
        console.log(quantityList);


      }
    });
  }
}

Vat function:

  sql.query("SELECT * FROM vat where number = ?", number, function (err, res) {
    if (err) {
      console.log("error: ", err);
      result(err, null);
      return;
    }

    if (res.length <= 0) {
      err = "Vat cannot be null";
      result({ error: "Vat not found" }, null);
      return;
    }

    console.log("Found vat: ", res[0].id);
    result(null, res[0].id);
    return;
  });
};
Dray
  • 1
  • 2
  • You should "promisify" your Vat function and then await it in the loop. Right now you're firing-and-forgetting. – Christian Dec 07 '20 at 15:28
  • Do you mean to just wrap vat function in promise? – Dray Dec 07 '20 at 15:34
  • Yes, see answer below. – Christian Dec 07 '20 at 15:36
  • I should clarify that you're not really firing-and-forgetting but the callback function to your Vat.checkNumber call isn't await:ed in the loop. – Christian Dec 07 '20 at 15:39
  • Okey. Now I understand. But in your answer you have skipped second parameter **Vat.checkNumber = function (number, result) { ** result. Can i just skip this result like you? Can you explain it to me? I'm a bit confused with callbacks. – Dray Dec 07 '20 at 15:44
  • I mean how can I get this console.log(err) if I dont return error message from function? – Dray Dec 07 '20 at 15:48
  • True, my bad. You will need a catch block for this. Will update the answer. – Christian Dec 07 '20 at 15:49
  • Thanks for helping me out. You are great. – Dray Dec 07 '20 at 15:51

1 Answers1

0

Try this:

async function checkNumber(number) {
  return new Promise((resolve, reject) => {
    sql.query('SELECT * FROM vat where number = ?', number, function(err, res) {
      if (err) {
        console.log('error: ', err);
        reject(err);
        return;
      }

      if (res.length <= 0) {
        err = 'Vat cannot be null';
        reject({ error: 'Vat not found' });
        return;
      }

      console.log('Found vat: ', res[0].id);
      resolve(res[0].id);
    });
  });
}

and then

for (const product of productArr) { //iterate through products

  console.log("start error: ", error); // <---- 
  if (error == 1) {
    console.log("stop");
    break;
  }

  //check if product's vat exists in vat table, if not add new
  let data; 
  try {
    data = await checkNumberPromisified(product.vat);
    if (!data) {
      console.log("not found");
      error = 1;
    } else {
      console.log("found");
      const vat_id = data;

      //crete new product obj json
      let newProduct = {
        vat_id: vat_id,
        name: product.name,
        price: product.price
      };

      //store product list and their quantity to use later in sql query
      productList.push(newProduct);
      quantityList.push(product.quantity);
      console.log(productList);
      console.log(quantityList);
    }
  }
  catch (err) {
    console.log(err);
    error = 1;
  }
}
Christian
  • 7,433
  • 4
  • 36
  • 61
  • throw err; // Rethrow non-MySQL errors ^ TypeError: result is not a function – Dray Dec 07 '20 at 15:50
  • Like I said, you skipped result function so now I should refractor it and delete it from function parameters, sure? – Dray Dec 07 '20 at 15:51
  • I changed the answer to manually promisifying the checkNumber function. Hope it helps. – Christian Dec 07 '20 at 16:03
  • Added async to function and now it works. So now I don't even need to make if (!data), cause if error occurs then it goes straight to catch, right? – Dray Dec 07 '20 at 16:09
  • Thanks for help. It confuse me cause it works without wraping function in promise like you did with checkNumber(). Is util.promisify doing it for us so we don't need to do this manually? – Dray Dec 07 '20 at 16:21
  • Yes, `promisify` would do it for you. I changed the answer bc I interpreted it as it didn't work using it. – Christian Dec 07 '20 at 19:39