Home > Mobile >  JS code after for loop runs before for loop finishes
JS code after for loop runs before for loop finishes

Time:11-09

I have a javascript application running on NodeJS. For context I am using the express framework as this is meant to be our backend. I have a chunk of code which is meant to get data from a database, filter it and then send it back to the client. Instead, the filtering happens AFTER the response is sent, meaning the client is getting incorrect data. The code is below.

let resultArray = [];
const bulkSearchPromise = new Promise((resolve, reject) => {
  for (let index = 0; index < input.length; index  ) {
    collectionPool.query('SELECT * FROM users WHERE '   type   ' = $1', [input[index]], (err2, result2) => { // Make a query for each input user is trying to search for
      if (err2) console.log("Error in bulk search: "   err2);

      else {
        if (result2.rows.length > 0) { // If input user searched for was found
          pool.query('UPDATE users SET usedsearches = usedsearches   1 WHERE id = $1', [result.rows[0].id]); // Increments used searches
          // The code below will filter useless key value pairs. For example if username: null then there is not a reason to send it back to the client
          let filteredArray = [];
          for (let index = 0; index < result2.rows.length; index  ) {
            let array = Object.entries(result2.rows[index]);
            let filtered = array.filter(([key, value]) => value != null);
            let filteredObject = Object.fromEntries(filtered);
            filteredArray.push(filteredObject);
            resultArray.push(filteredObject);
          }
          console.log("a"); // This should run first.
        }
      }
    });
  }
  resolve("ok");
})

bulkSearchPromise.then((value) => {
  console.log("b"); // This should run second
  return res.json({
    status: 'success',
    content: resultArray
  }); // resultArray should be populated after the filtering above. Instead it is empty.
})

When the endpoint is hit the output will always be

username
b
a

What I need is for the for loop to run first and then after resultArray is populated, return it back to the client.

I've tried wrapping this code into a promise, but that hasnt helped either as 'resolve("ok")' is still called before the for loop completes.

CodePudding user response:

Your promise is resolving before collectionPool.query is done.

The for loop only runs after collectionPool.query is done but you are resolving the promise before it. Note that collectionPool.query is async and the its callback will only run when the web-api is finished (if this concept is murky check this out http://latentflip.com/loupe)

Option 1:

Move resolve() inside the collectionPool.query (where the console.log("a");) call back and call resolve(filteredObject). In addition you should reject(err2) when err2 is not null (not just console)

Option 2:

you can use Util.Promisify to transform collectionPool.query to promise base API which will save you the hustle of manually transform

const util = require('util');

util.promisify(collectionPool.query)(QUERY)
  .then(queryRes => { 
     /* logic to refine queryRes to object */
     return filteredObject;
   })

in both options you can omit the resultArray from your code. if you resolve(filteredObject) or return filteredObject; in then() you will be able to access this data on the next then (the value in bulkSearchPromise.then((value)).

  • Related