robert robert - 5 months ago 19
Node.js Question

Do something async with underscore map

function addSomething(data) {
var defer = q.defer();
data = _.map(data, function(item) {
item['something'] = callSomethingAsync();
return item;
});
return defer.promise;
}


How can I handle this problem. The only way I found is using Async.js.
But maybe there is a better way using $q?

EDIT:

function getScopes(item) {
var defer = q.defer();
var query = "SELECT somevalue FROM Something WHERE ID = '" + item.id + "'";
mysql.query(query, function(err, data) {
if (err) {
defer.reject(err);
} else {
item[newkey] = data
defer.resolve(item);
}
});
defer.resolve(data)
return defer.promise;
}

//add necessary scopes to the audit
function addScopes(data) {
var promises = _.map(data, function(item) {
return getScopes(item);
});
return Promise.all(promises);
}


How I can prevent using defer in the getScopes function?

Edit 2:

var query = "SELECT * FROM tiscope";
Q.nfcall(mysql.query, query).then(function(data) {
console.log(data);
});


there is nothing returned.

Here is how I use mysql:

var sql = require('mysql');

var connection = sql.createConnection({
host : 'xxx',
user : 'xxx',
password : 'xxx',
database : 'xxx'
});

connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
} else {
console.log('mysql connection established');
}
});

module.exports = connection;


Maybe there is the mistake.

Answer

A lot of promise libraries provide a map function. Seems Q does not. No matter the the same can be accomplished with vanilla promises (and Q) anyway using the all function.

First things first. Avoid defer. It makes code more difficult to reason and maintain. There are only a few rare cases when defer is needed. The rest of the time a normal promise constructor/helper functions will work better.

Normal Promises Example

function addSomething() {
  var promises = _.map(data, function(item) {
    return callSomethingAsync(item);
  });
  return Promise.all(promises);
}

Q Promises Example

function addSomething() {
  var promises = _.map(data, function(item) {
    return callSomethingAsync(item);
  });
  return $q.all(promises);
}

Presumably callSomethingAsync returns a promise. If not use the promise constructor pattern:

function toPromise(asyncFn, args) {
  return new Promise(function (resolve, reject) {
    function callback(err, result) {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    }
    asyncFn(callback, args);
  });
}

function addSomething() {
  var promises = _.map(data, function(item) {
    return toPromise(callSomethingAsync, item);
  });
  return Promise.all(promises);
}