1

I have a problem with the asynchrony of nodejs. Hope you can help me.

exports.DeviceInfo = function(req, res, next) {
  var nets = req.body.networks;

  db.collection("device", function(err, deviceConf) {
    var detected_beacons = [];

    if (!err) {
      for (var i = 0; i < nets.length; i++) {
        deviceConf
          .find({
            "data.number": nets[i]
          })
          .toArray(function(errFind, saver) {
            if (!errFind && saver) {
              saver.forEach(function(disp) {
                var detected = {};
                detected.address = disp.address;
                detected_beacons.push(detected);
                console.log(detected_beacons);
              });
            }
          });
      }
      console.log(detected_beacons);
      res.json(detected_beacons);
    } else {
      console.error(err);
      res.status(500);
      res.json({
        message: "Couldn't connect to database"
      });
    }
  });
};

If I write some logs, we could see which is the problem. The detected_beacons is being returned before the for clause. I want to be returned after for in order to be full of data. I have read about callbacks and promises but I don't know how to use them in my code.

image

5
  • Look at the comments to stackoverflow.com/q/39288896/18771. You have the exact same mistake in your code. Commented Sep 2, 2016 at 10:37
  • I've changed the for loop with forEach but same issue. Commented Sep 2, 2016 at 10:47
  • No error appears, but the results are the same. @Tomalak Commented Sep 2, 2016 at 11:02
  • Promise.all( ... ).then( ... ) is your friend. Commented Sep 2, 2016 at 11:13
  • I have tried to use it but I don't know where to write in my code @moon Commented Sep 2, 2016 at 11:19

2 Answers 2

1

Try this code. you cannot do a for loop concerning callback functions.

exports.DeviceInfo= function(req,res,next){
var nets = req.body.networks;
db.collection("device", function(err, deviceConf){
    var detected_beacons = [];
    var netSize = nets.length;
    var beaconsLoop = function(i) {
        deviceConf.find({"data.number" : nets[i]}).toArray(function(errFind, saver){
                if (!errFind && saver){
                    var saverSize = saver.length;
                    saver.forEach(function(disp){
                        var detected = {};
                        detected.address = disp.address;
                        detected_beacons.push(detected);
                        saverSize--;
                        if (saverSize == 0) {
                            if (i != netSize - 1) {
                                i++;
                                beaconsLoop(i);
                            } else {
                                res.json(detected_beacons);
                            }
                        }
                    });
                }
            });
    };

    if (!err){
        if (netSize > 0) beaconsLoop(0);
    } else {
        console.error(err);
        res.status(500);
        res.json({message:"Couldn't connect to database"});
    }
});

};

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

1 Comment

There was an option not contempled, if the saver empty. Correcting that repeating if (i != netSize - 1) { i++; beaconsLoop(i); } else { res.json(detected_beacons); } . Your solution was fantastic. Thanks!
0

I made a simple solution using map:

if (!errFind && saver) {
  var detected_beacons = saver.map(function(disp) {
    return {
      address: disp.address
    };
  });

  console.log(detected_beacons);
  res.json(detected_beacons);
}

Here is full code.

1 Comment

This is also valid but it does not solve the asynchrony issue @Nie, the detected_beacons continue to be sent first and empty.

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.