0

I'm having a bit trouble understanding the execution order when my async function starts to be "complexed".

I have the following function which is an async function that has inside another lodash each async loop as follows:


this.addItem = async (params, ingredients) => {
    try {
      
      var ings = [];
      if (!_.isEmpty(params.ings)) {
        if (!_.isEmpty(ingredients)) {
          _.each(params.ings, async i => {
            try {
              if (_.map(ingredients, 'name').includes(i)) {
                ings.push(_.filter(ingredients, ing => ing.name === i)[0].id);
                return true;
              } else {
                var ing = await ingsFn.addIngredientAndRetrieve(i);
                ings.push(ing);
                return true;
              }
            } catch (e) {
              console.log(e)
            }
          });
        } else {
          _.each(params.ings, async i => {
            try {
              var ing = await ingsFn.addIngredientAndRetrieve(i);
              ings.push(ing);
              return true;
            } catch (e) {
              console.log(e)
            }
          });
        }
        
      }
      
      await connection.query('INSERT INTO items (name, parent_id, description, price, veg, spicy, ings, algs, published) VALUES (?,?,?,?,?,?,?,?,?)', [
        params.name, params.parent_id, params.desc, params.price, params.veg, params.spicy, JSON.stringify(ings), JSON.stringify(params.algs), params.published
      ]);

      return true;
    } catch(e) {
      console.log(e.message);
      return false;
    }
  }

I'm creating a Ings empty array and then try to push to it ids - the function does work but then when I try to enter ings into my query at the bottom of the function I always get an empty array. I understand it just doesn't wait for everything to be finished on the async each loop.

So my questions are

  1. why isn't it waiting even though i use async and await. Maybe i have an understanding issue on the flow of things when working with multiple asyncs?
  2. Is it really necessary for each async function to have a try catch? or the functions' main one will catch them all? it gets kind if sloppy to put so much tries and catch in one function and i would like it to be more readable. the question is if i can throw from anywhere (even from inside another async function like the _.each i use.

Hope i'm clear enough. Thanks in advance for clearing it up for me guys.

fedesc
  • 2,554
  • 2
  • 23
  • 39

1 Answers1

1

why isn't it waiting even though i use async and await

Because _.each doesn't pay any attention to the promise your async function returns to it, it just moves on to the next iteration.

Instead of _.each, use for-of.

Is it really necessary for each async function to have a try catch?

No, not at all. You only need to catch and handle errors at the top level of your code. That might be a try/catch around the entire body of a top-level async function, or it might be using .catch to register a rejection handler when calling the top-level async function from your non-async code.


FWIW, here's that function rewritten with for-of. There's lots of code there you just don't need.

this.addItem = async (params, ingredients) => {
    const ings = [];
    // No need for an empty check on `params.ings`, the loop just will never
    // go into the loop body
    for (const ing of params.ings) {
        // No need for an empty check on `ingredients`, `find` just won't find anything
        const found = ingredients.find(({name}) => name === ing);
        if (found) {
            ings.push(found.id);
        } else {
            ings.push(await ingsFn.addIngredientAndRetrieve(ing));
        }
    }
      
    await connection.query('INSERT INTO items (name, parent_id, description, price, veg, spicy, ings, algs, published) VALUES (?,?,?,?,?,?,?,?,?)', [
        params.name, params.parent_id, params.desc, params.price, params.veg, params.spicy, JSON.stringify(ings), JSON.stringify(params.algs), params.published
    ]);

    return true;
};

Catch errors and handle them when calling the function. Or, if this should be a function that never throws (like an event handler), put a single try/catch around its logic.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875