0

how to callback timer() function after forEach loop is finished, using the same code. or is there is a better way to loop through each user with delay then after the loop is done, the timer() is called back using forEach.

  const usersProfile = () => {
  let interval = 1000;
  let promise = Promise.resolve();
  db.select('*').from('users')
    .returning('*')
    .then(users => {
      users.forEach((user, index) => {
        setTimeout(function(){

        }, index * 1000)
        db.select('*').from(`${user.name}`)
          .returning('*')
          .then(userdata => {
            userdata.forEach(data => {
                promise = promise.then(function(){
                  if(data.status === 'online'){
                    console.log(`${data.name} ${data.items} ${data.profile} ${data.images}`)
                  }
                return new Promise(function(resolve){
                    setTimeout(function(){
                      resolve();
                    }, interval)
                })
              })
            })
          })
      })
       timer();
    })
}
const timer = () => {
  setTimeout(usersProfile, 1000)
}
timer();

===============ALL THE ABOVE ARE MY OLD CODE ================ but thanks to https://stackoverflow.com/users/2404452/tho-vu it solved most of the problem but can i do this to serve the purpose of the app

const usersProfile = async () => {
  let interval = 1000;

  const delayPromise = (data, delayDuration) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        if(data.status === 'online'){
          console.log(`${data.name} ${data.items} ${data.profile} ${data.images}`);
          resolve();
        }
      }, delayDuration)
    });
  };

 const userInfo = (data, delayDuration) => {
    return new Promise((resolve) => {
      setTimeout(() => {
          console.log(`${data.info}`);//info about user from his table each user has his own table besides users table that has only the user tables
          resolve();
      }, delayDuration)
    });
  };
  try {
    const userData = await db.select('*').from('users').returning('*');
    const promises = userData.map((data, index) => delayPromise(data, index * interval));
    const userData = await db.select('*').from(`${data.name}`).returning('*');
    const info = userData.map((data, index) => userInfo(data, index * interval));
    await Promise.all(promises);
    // here you can write your effects
  } catch (e) {
    console.log(e);
  }
}
The pyramid
  • 313
  • 1
  • 6
  • 18

2 Answers2

2

Another approach using async-await to avoid callback hell.

const usersProfile = async () => {
  let interval = 1000;

  const delayPromise = (data, delayDuration) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        if(data.status === 'online'){
          console.log(`${data.name} ${data.items} ${data.profile} ${data.images}`);
          resolve();
        }
      }, delayDuration)
    });
  };

  try {
    const userData = await db.select('*').from('users').returning('*');
    const promises = userData.map((data, index) => delayPromise(data, index * interval));
    await Promise.all(promises);
    // here you can write your effects
  } catch (e) {
    console.log(e);
  }
}
blaz
  • 3,981
  • 22
  • 37
  • const userData = await db.select('*').from('users').returning('*'); can i call data from this code like this const userData = await db.select('*').from(`${data.name}`).returning('*'); so i can run the second loop to grab the info in each table that i created for each user – The pyramid Oct 22 '18 at 03:21
  • @The4thpyramid Yes you can, but `delayPromise` might need to be changed to meet the modification. Personally, I suggest you to look for a better db query, e.g. a join query for getting all user personal data in one db.select, not by chaining queries like you intended to. – blaz Oct 22 '18 at 04:35
0

it is hard for me to fully understand what you wanted to accomplish through the code, but I will try to explain what you can do to solve the issue.

First of all, if you want to wait for multiple promises, you should use Promise.all and not promise = promise.then

You can do this as so:

let promises = [];
users.forEach((user, index) => {
   let promise = db.select(*).from('users') //should return a promise
   promises.push(promise);
});

//promises have already started to execute (in parallel)

Promise.all(promises)
.then(() => console.log('all promises finished successfully'))
.catch((e) => console.error('received error at one of the promises'));


 // when the program arrives here we know for a fact that either all promises executed successfully or one of the promises failed

timer();

Explanation: because promises execute asynchronously the forEach() function does not wait for any of the promises created to finish, so the solution is to wait for all of them at then after the entire loop.

This means the promises are created, and are being executed while the forEach() loop executes, in parallel, and when the program reaches Promise.all it stops and waits for all of them to finish.

Second, I would strongly advice you to use functions as a way to simplify your code, that way it would be easier for you to grasp every thing that is happening, even if its complicated.

Good luck !

orpris12
  • 156
  • 3