1

I would like to run a function after the for loop done looping, but in my case the function after the for loop runs before the loop even finished. Here's my code

let orderedItems = [];

for (let i = 0; i < orderCode.length; i++) {
  menuModel.findOne({
    _id: orderCode[i]
  }, (err, order) => {
    if (order) {
      orderedItems.push(order.name);
    }
  });
}

console.log(orderedItems); // all the tasks below run before the loop finished looping

let orderData = new orderModel();
orderData._id = helpers.createRandomString(5).toUpperCase();
orderData.username = username;
orderData.orderCode = orderCode;
orderData.orderedItems = orderedItems;
orderData.totalPrice = 5;

orderData.save((err) => {
  if (err) {
    console.log(err);
    callback(500, {
      'Error': '1'
    });
  }
  callback(200, {
    'Message': 'Successfully ordered'
  });
});   
Manish Balodia
  • 1,863
  • 2
  • 23
  • 37
Kemal Dwiheldy
  • 409
  • 1
  • 4
  • 14
  • because everything is executed asynchronously. You can wrap the for loop in a promise and when that is done can execute the rest of the code – Rishikesh Dhokare Aug 02 '18 at 11:21
  • Possible duplicate of [How could I run a function after the completion of a for loop in Node.js?](https://stackoverflow.com/questions/27914209/how-could-i-run-a-function-after-the-completion-of-a-for-loop-in-node-js) –  Aug 02 '18 at 11:22

1 Answers1

2

as @RishikeshDhokare said everything is executed asynchronously. so the trick is to split the tasks into separate functions.

so first we execute an async function you can use promises or async await

then we say after all the async tasks have been completed do the save task.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

const orderCode = [1, 2, 3]
const menuModel = {
  findOne: item => new Promise(resolve => resolve({
    _id: item._id,
    name: 'name'
  }))
}

class orderModel {
  save(cb) {
    return cb(null)
  }
}
/*
  ignore all above here i'm mocking your funcs 
  and vars so that the code works
*/

let orderedItems = [];

function getAllOrderedItems() {
  const promises = orderCode.map(id => {
    return menuModel.findOne({
      _id: id
    });
  })
  console.log('...start the request')
  // fire  all async items then resolve them all at once
  return Promise.all(promises)
    .then((data) => {
      console.log('...finished all requests')
      return orderedItems.concat(data);
    })
    .catch(err => console.log(err))
}

function handleSave(data) {
  let orderData = new orderModel();
  console.log(data)
  console.log('...start save')
  orderData.save((err) => {
    console.log('...save finished')
  });
}
//do all the async tasks then do the save task
getAllOrderedItems()
  .then((data) => handleSave(data))
Joe Warner
  • 3,335
  • 1
  • 14
  • 41