0

I am a newbie in JavaScript and I am a bit stuck with the async way JS executes code...

Here is my code :

   var marketPlaces = []
   body.rows.forEach(function(doc) {
    marketPlacesDB.get(doc.id, function(err, body){
      if (err) {
        callback(err, null)
      } else {
        console.log("Ajout d'une marketplace")
        marketPlaces.push({id: body._id, name: body.name})
      }
    })
  })

  console.log("Retour des résultats")
  callback(null, { marketPlaces: marketPlaces })

body.rows is an array containing ids of objects I would like to return in the marketPlaces array. For each element, I need to make a new request to the database to get the details of the objects (here only the "name").

The result is an empty array because the foreach loop ends before the callbacks of the get function return.

I can't figure out how to make this "synchronous".

Thanks for your answers. Philippe.

Darth Philou
  • 134
  • 1
  • 9
  • What database are you using? It probably has a promise interface that would make this easier with `Promise.all()`. – jfriend00 Aug 26 '17 at 18:43
  • 1
    Once you get yourself into an asynchronous (retarded) timeline with `marketPlacesDB.get(doc.id, function(err, body){...` there is no way out from that timeline unless you have a time machine to make you leap to the future. You have to do everything (including new async calls) within that function. – Redu Aug 26 '17 at 20:47

3 Answers3

0

If they didn't give you the synchronous API, you can't.

But you can still make it works 'synchronous' by adding a big callback. (I'm a non-native English speaker, dunno what word should I use here)

let counter = 0;
const max = marketPlacesDB.getLength();    // base on the real situation
function regularCallback() {
    /* your callback */
    if(++counter == max)
        bigCallback();
};
function bigCallback() {
    // continue on your original work
}
Nianyi Wang
  • 712
  • 6
  • 13
0

You can't make it synchronous if marketPlaceDb is not providing api. But you can make it work with asynchronous version too:

var async = require('async')

function getMarketPlaces(callback) {
    var marketPlaces = []

    async.eachSeries(body.rows, doc, function (next) {
        marketPlacesDB.get(doc.id, function(err, body){
            if (err) {
                next(err, null) // finish async operation
            } else {
                marketPlaces.push({id: body._id, name: body.name})
                next() // go next iteration
            }
        })
    }, function (err) {
        // eachSeries done
        // here is marketPlaces
        console.log("Retour des résultats")
        callback(err, { marketPlaces: marketPlaces })
    })

}

getMarketPlaces(console.log)

I used 'async' library from npm and eachSeries method to iterate array asynchronously.

Ozgur
  • 3,738
  • 17
  • 34
  • Hello Ozgur. Its seems you are the one who really understood my question ;-) (I put "synchronous" between quotes ;-) ). But your code does not work directly. I post the actual answer. – Darth Philou Aug 27 '17 at 15:09
0

Thanks to Ozgur using async library seems to be the most elegant way to answer my question.

The correct code is :

var marketPlaces = []

async.eachOfSeries(body.rows, function (item, key, next) {
    marketPlacesDB.get(item.id, function(err, body){
        if (err) {
            next(err, null)
        } else {
            marketPlaces.push({id: body._id, name: body.name})
            next()
        }
    })
}, function (err) {
    console.log("Retour des résultats")
    callback(err, { marketPlaces: marketPlaces })
})
Darth Philou
  • 134
  • 1
  • 9