1

I'd like to use map() in NodeJS to change items of my array before rending an EJS template.

However, sometimes the map() is not finished before the render and I get an error 500...

My code :

 var newCards = cards.map(function(card) {
    switch(card.display) {
      case 'number':
        dbConnexion.query(card.query).success( function(results) {
          card.results = results.length;
        });
        break;
      case 'table':
        dbConnexion.query(card.query).success( function(results) {
          card.results = results;
        });
        break;
    }
  return card;
});
response.render('myview', {
  newCards: newCards
});
tonymx227
  • 5,293
  • 16
  • 48
  • 91

3 Answers3

2

You are using async functions within map, you should promisify your map and wait promises to complete.

let promises = cards.map(function(card) {
  return new Promise(function(resolve, reject) {
    switch(card.display) {
      case 'number':
        dbConnexion.query(card.query).success( function(results) {
          card.results = results.length;
          resolve(card);
        });
        break;
      case 'table':
        dbConnexion.query(card.query).success( function(results) {
          card.results = results;

          resolve(card);
        });
        break;
    }
  });
});

Promise.all(promises).then(() => {
  response.render('myview', {
   newCards: newCards
  });  
});
0

You need to render after the callbacks have returned. The easiest way (with the minimal change to existing code) is to use Promises.

var promises = [];

var newCards = cards.map(function(card) {
  if (card.type == = 'query') {
    switch (card.display) {
    case 'number':
      promises.push(new Promise(function(resolve, reject) {
        dbConnexion.query(card.query).success(function(results) {
          card.results = results.length;
          resolve();
        });
      }));
      break;
    case 'table':
      promises.push(new Promise(function(resolve, reject) {
        dbConnexion.query(card.query).success(function(results) {
          card.results = results.length;
          resolve();
        });
      }));
      break;
    }
  }
  return card;
});

Promise.all(promises).then(function() {
  response.render('glovebox', {pages : pages, newCards : newCards});
});

Error handling is left as an exercise (reject the promise inside the map, then call .catch on the final Promise object)

T Tse
  • 786
  • 7
  • 19
0

You have a similar problem to How do I return the response from an asynchronous call?

Your call to the database is asynchronous here

dbConnexion.query(card.query).success( function(results) {
          card.results = results.length;
        });

Have a look at the above question for strategies to deal with it.

Peter Grainger
  • 4,539
  • 1
  • 18
  • 22