1

I'm trying to get list of virtual communities on my Node.js app and then return it with callback function. When i call a getList() method with callback it returns a empty array.

const mysqli = require("../mysqli/connect");

class Communities{

  getList(callback){
    var list = [];

    mysqli.query("SELECT * FROM communities", (err, communities) => {

      for(let i = 0; i < communities.length; i++){
        mysqli.query("SELECT name FROM users WHERE id='"+ communities[i].host +"'", (err, host) => {

          list.push({
            "id": communities[i].id,
            "name": communities[i].name,
            "hostID": communities[i].host,
            "hostName": host[0].name,
            "verified": communities[i].verified,
            "people": communities[i].people
          });

        });
      }

      callback(list);
    });
  }

}

new Communities().getList((list) => {
  console.log(list);
});

I need to make for loop to asynchronous and call callback when for loop ends. Please let me know how to do this. Thanks.

4
  • Which mysqli library are you using? Commented Apr 22, 2019 at 12:46
  • This one. npmjs.com/package/mysql Commented Apr 22, 2019 at 12:48
  • It's probably related to the fact the for loop is synchronous. So, the callback happens before the loop itself. As you are working with callbacks, you may use some async flow using it. Async is a great library to handle this Commented Apr 22, 2019 at 12:54
  • Yes, this is the main problem of it because callback happens before the loop like you wrote, but i don't know how to use that library well. Commented Apr 22, 2019 at 12:56

1 Answer 1

2

Callbacks get really ugly if you have to combine multiple of them, thats why Promises were invented to simplify that. To use Promises in your case you have to create a Promise first when querying the database¹:

 const query = q => new Promise((resolve, reject) => mysqli.query(q, (err, result) => err ? reject(err) : resolve(result)));

Now doing multiple queries will return multiple promises, that can be combined using Promise.all to one single promise²:

 async getList(){
   const communities = await query("SELECT * FROM communities");

   const result = await/*³*/ Promise.all(communities.map(async community => {
      const host = await query(`SELECT name FROM users WHERE id='${community.host}'`);/*⁴*/

       return {
        ...community,
        hostName: host[0].name,
       };
    }));

    return result;
  }

Now you can easily get the result with:

 new Communities().getList().then(list => {
   console.log(list);
 });

Read on:

Working with Promises - Google Developers

Understanding async / await - Ponyfoo

Notes:

¹: If you do that more often, you should probably rather use a mysql library that does support promises natively, that safes a lot of work.

²: Through that the requests are done in parallel, which means, that it is way faster than doing one after another (which could be done using a for loop & awaiting inside of it).

³: That await is superfluous, but I prefer to keep it to mark it as an asynchronous action.

⁴: I guess that could also be done using one SQL query, so if it is too slow for your usecase (which I doubt) you should optimize the query itself.

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

6 Comments

Thanks, i will try it.
When i run the script, console returned error with: SyntaxError: await is only valid in async function and i have already installed a async library via npm.
You don't need any library. Is your NodeJS version up to date? Have you used the exact code provided? Which of the awaits ?
Right now i have 8.11.1 version of Node.js and 5.6.0 of npm.
Yes, i used the code you sent and it is this await: var communities = await query("SELECT * FROM communities");
|

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.