0

Problem resolved on Asynchronously solution to check data from database kinds of loop clause

with this below code i can generate simple array as jsonArray into checkUserMobileNumberAsEwallet function, but i can't pass it out of that to send inside client,

with socket.emit('syncContacts', accountNumbers) i get [] result on accountNumbers, but into if (success) { statement array successful created and pushed into accountNumbers array

socket.on('syncContacts', function (data) {
    var accountNumbers = [];

    for (var i = 0; i < data.length; i++) {
        checkUserMobileNumberAsEwallet(data[i].mobileNumber, function (success) {
            if (success) {
                accountNumbers.push({ewalletNumber: this.mobileNumber});
                console.log(accountNumbers);
            }
        }.bind({mobileNumber: data[i].mobileNumber}));
    }
    console.log(accountNumbers);

    socket.emit('syncContacts', accountNumbers);
});

function checkUserMobileNumberAsEwallet(mobileNumber, callback) {
    var mobileNumber = mobileNumber.substr(1, mobileNumber.length);

    var query = "SELECT id FROM userEwallets WHERE ewalletNumber LIKE '%" + mobileNumber + "'";
    connection.query(query, function (err, results) {
        if (err) return callback(false);

        if (results.length === 0)
            return callback(false);
        else {
            return callback(true);
        }

    });
}

Updated after post comments:

socket.on('syncContacts', function (data) {

    //console.log(accountNumbers);

    //socket.emit('syncContacts', accountNumbers);

    async.parallel(
        [
            function (callback) {
                var accountNumbers = [];

                for (var i = 0; i < data.length; i++) {
                    checkUserMobileNumberAsEwallet(data[i].mobileNumber, function (success) {
                        if (success) {
                            accountNumbers.push({ewalletNumber: this.mobileNumber});
                            console.log(accountNumbers);
                        }
                    }.bind({mobileNumber: data[i].mobileNumber}));
                }
                callback(success, accountNumbers);
            }
        ],
        function (success, results) {
            console.log("results " + results.toString());
            socket.emit('syncContacts', results);
        });
});

function checkUserMobileNumberAsEwallet(mobileNumber, callback) {
    var mobileNumber = mobileNumber.substr(1, mobileNumber.length);

    var query = "SELECT id FROM userEwallets WHERE ewalletNumber LIKE '%" + mobileNumber + "'";
    connection.query(query, function (err, results) {
        if (err) return callback(false);

        if (results.length === 0)
            return callback(false);
        else {
            return callback(true);
        }
    });
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
mahdi pishguy
  • 994
  • 1
  • 14
  • 43

2 Answers2

0

Based on our code, it seems like checkUserMobileNumberAsEwallet is an asynchronous event, which accepts a function callback. That would mean that the for-loop would execute, which would queue up executions to checkUserMobileNumberAsEwallet. Immediately after the for-loop executes, console.log would correctly output the empty array accountNumbers and emit the event through the socket. Then the callback functions to each checkUserMobileNumberAsEwallet execution would begin to execute, and log the accountNumbers array which now has data.

This can be solved in a few ways, but likely the easiest and most readable would be to create Promises, and act on the Promises when they resolve. Personally I like the 'when' promise library, but many libraries could help to solve this problem. https://github.com/cujojs/when/blob/master/docs/api.md#whensettle

Michael Camden
  • 1,183
  • 8
  • 9
0

The problem is that you have no control over when the code inside the callback executes, and it ends up executing after you've already called socket.emit.

You can either a) use an async aggregator to call a callback for each successful mobile number and then, when all of those have finished, call the socket.emit call OR b) do something like what I did below. Alter your checkUserMobileNumberAsEwallet function to accept and verify an array of mobile numbers, and pass the successful numbers to your callback function

Try the following:

socket.on('syncContacts', function (data) {
  var accountNumbers = [];
  var mobileNumbers = [];

  for (var i = 0; i < data.length; i++) {
    mobileNumbers.push(data[i].mobileNumber);
  }

  checkUserMobileNumberAsEwallet(mobileNumbers, function (successfulNumbers) {
      if (successfulNumbers.length > 0) {
          for (var i = 0; i < successfulNumbers.length; i++) {
              accountNumbers.push({ewalletNumber: successfulNumbers[i]});
          }
          socket.emit('syncContacts', accountNumbers);
      }
   }.bind({mobileNumbers: mobileNumbers}));
});
dshapiro
  • 1,075
  • 14
  • 24