I am using the when library with Node js. I create a deffered object, place the resolve inside an encapsulated Mongoose findOne() function, and return the promise outside. But it seems my promise is always returned before the data is retrieved.
User.prototype.getProfile = function(criteria) {
var deferred = when.defer();
var options = {
criteria: criteria,
select: 'name id email'
};
this.User.load(options, function(err, data) {
if (data) {
this.name = data.name;
this.email = data.email;
this.id = data.id;
} else {
return false;
}
console.log(data);
deferred.resolve();
});
console.log('returning promise');
return deferred.promise;
};
Caller
User.getProfile(req.query).then(
function success(data) {
res.send('Hello ' + User.name);// Hello ''
}
);
Outputs 'returning promise'
before the data
Yes, promise will be returned to the caller instead of the data and that is how we can take advantage of the asynchronous functions. This is the common sequence of actions in handling async calls,
Make an async call.
Return a Promise
to the caller.
At this point, caller doesn't have to wait for the result. It can simply define a then
function, which knows what to do when the data is ready and move on to the next task.
Later point of time, resolve (or reject, if failed) the promise when you get the result from the async call.
Execute the then
function on the Promise
object, with the result from the async call.
So, your code will have to be modified a little bit, like this
User.prototype.getProfile = function(criteria) {
var deferred = when.defer();
var options = {
criteria: criteria,
select: 'name id email'
};
this.User.load(options, function(err, data) {
if (err) {
// Reject, if there is an error
deferred.reject(err);
} else {
// Resolve it with actual data
deferred.resolve(data);
}
});
return deferred.promise;
};
Then your caller will do something like this
userObject.getProfile()
.then(function(profileObject) {
console.log(profileObject);
// Do something with the retrieved `profileObject`
})
.catch(function(err) {
console.err("Failed to get Profile", err);
});
// Do something else here, as you don't have to wait for the data
Here, caller just calls getProfile
and attaches a function which says what to do with the returned data and moves on.
Edit If you want the same object to be updated, then you can simply use similar code, but you need to preserve this
in some other variable, because the binding of this
happens at runtime.
User.prototype.getProfile = function(criteria) {
var deferred = when.defer();
var options = {
criteria: criteria,
select: 'name id email'
};
var self = this;
this.User.load(options, function(err, data) {
if (err) {
// Reject, if there is an error
deferred.reject(err);
} else {
self.name = data.name;
self.email = data.email;
self.id = data.id;
}
deferred.resolve(data);
});
return deferred.promise;
};