making mongoskin function is asynchronous sync

1.1k views Asked by At
User.prototype.isUnique = function () {
    var result;
    db.user.count({name:'abcdefg'}, function(err, count){
        console.log('the count is: ' + count);
        result = count;
    });
    return result;
}

this function is used to find out if this user is unique, but the return result is always 'undefined' since db operation is async. I believe it is a common problem in nodejs. How do I solve it?

I try to use promise (https://npmjs.org/package/promise), but I don't have enough knowledge to understand their documentation. It's for very advanced developer.

Can you help me with some sample code? All I need to do is get the count() using mongoskin, and then return the result in this member method.

Thanks!

1

There are 1 answers

3
robertklep On BEST ANSWER

It's not a common problem, it's just how Node works and something that you'll have to get used to dealing with.

The simplest solution (also a very common one) is to provide a callback function from the calling code. That function will be called whenever the asynchronous action is finished:

User.prototype.isUnique = function(callback) {
  db.user.count({name:'abcdefg'}, function(err, count){
    console.log('the count is: ' + count);
    callback(err, count);
  });
}

// in your calling code:
user.isUnique(function(err, count) {
  if (err) ...; // TODO: handle error
  ...
});

It's also common in Node to have callback functions accept at least one argument which contains an error object if an error occurred, or null if everything went okay.

In the code above I'm passing any errors that may have occurred during the call to db.user.count to the callback function. It's up to the calling code to deal with any errors.

There are several alternatives to dealing with asynchronous code. One would be to use promises, like you mention. There are also solutions like streamline that make asynchronous code look like it is synchronous, but it requires that you 'compile' your code (although this can also be done at runtime) before you can use it.

EDIT: if you want to use promises, you can use this:

var Promise = require('promise');

User.prototype.isUnique = function() {
  return Promise(function(resolve, reject) {
    db.user.count({name:'abcdefg'}, function(err, count){
      if (err) {
        console.log('an error occurred:', err);
        reject(err);
      } else {
        console.log('the count is:', count);
        resolve(count);
      }
    });
  });
};

// in your calling code:
user.isUnique().then(function(count) {
  ...
}, function(err) {
  ...
});

(this requires that the promise package is installed)