4

I want to get the allItems variable outside the function, but I just can get an empty array. The first console.log shows the array I wanted, but the second it's just [].

var allItems = [];    
orderPads.forEach(async  element => {
        
        element.orders_fk.forEach(async elem => {
            
            let itemsArray = await OrderedItem.find({ order_fk: elem });
            
            
            itemsArray.forEach(async e => {
                 
                let temp = e.toObject();
                const mesa = await Table.findById(element.mesa);
                temp.mesa = mesa.name;
                
                allItems.push(temp)
                console.log(allItems)
                
            })
        })
    });
console.log(allItems)

I've already looked for answers online, but nothing seems to work in this case. Thank you for the help!

1
  • 1
    Async and forEach does not work together. Either use asyncForEach or use a simple for loop. Commented Sep 18, 2020 at 22:29

1 Answer 1

4

Async functions don't do what you think they do in forEach. Foreach will wait for every loop, but since it won't return a Promise, you can't actually wait for all loops (the forEach) to be done - the method will just return the current null immediately. Then you log that once. You might notice that your last log is logged first, and your others later, indicating that forEach was completed, but the loops completed later, and your array only filled up after your first log.

Personally, I would suggest using a for loop itself instead, which does not actually take you out of the async flow:

const allItems = [];   

for( const element of orderPads ){
for( const elem of element.orders_fk ){

  const itemsArray = await OrderedItem.find({ order_fk: elem });
  
  for( const e of itemsArray ){
  
    const temp = e.toObject();
    const mesa = await Table.findById(element.mesa);
    temp.mesa = mesa.name;

    allItems.push(temp)
    console.log(allItems)
    
  }
  
}}

console.log(allItems)

for loops are core constructs in Javascript, while forEach is in essence a simplistic wrapper for a for loop in Arrays that was never intended for asynchronous use.

Sign up to request clarification or add additional context in comments.

4 Comments

.forEach() will NOT wait for every loop. It is not promise aware and pays zero attention to what the callback returns. It does NOT wait for an async function to resolve its promise. Your recommendation to switch to a for loop is correct. .forEach() use should basically be discontinued now because for loops are so much more powerful these days and can be optimized better by the compiler and will wait for await, and have flow control with continue, break, return, etc.... .forEach() will do none of those.
Thank you so much for both answers somethinghere and @jfriend00 ! Not just I got my problem solved, but I learned a lot. Hope you guys have a great day!
Nice! Happy to help, good luck javascripting! Async seems complex, just keep in mind that everything you want to wait for needs to be async or you will see unexpected behaviour!
@jfriend00 Don't forget about labels for loops - so useful when you start nesting for loops (which are happening in this question). myLabelLoop: for( const thing of set ) break myLabelLoop;. So useful. So easy to control. I have stopped using forEach in 99% of the cases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.