Отложенный объект возвращается до разрешения
Я использую библиотеку когда с Node js. Я создаю отложенный объект, помещаю разрешение в инкапсулированную функцию Mongoose findOne() и возвращаю обещание снаружи. Но, похоже, мое обещание всегда возвращается до получения данных.
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;
};
гость
User.getProfile(req.query).then(
function success(data) {
res.send('Hello ' + User.name);// Hello ''
}
);
Выходы 'returning promise'
перед data
3 ответа
Да, обещание будет возвращено вызывающей стороне вместо данных, и именно так мы сможем воспользоваться асинхронными функциями. Это обычная последовательность действий при обработке асинхронных вызовов,
Сделайте асинхронный вызов.
Вернуть
Promise
для звонящего.На этом этапе звонящему не нужно ждать результата. Он может просто определить
then
функция, которая знает, что делать, когда данные готовы, и переходить к следующей задаче.Через некоторое время разрешите (или отклоните, если не удалось) обещание, когда получите результат от асинхронного вызова.
Выполнить
then
функция наPromise
объект, с результатом асинхронного вызова.
Таким образом, ваш код должен быть немного изменен, как это
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;
};
Тогда ваш абонент сделает что-то подобное
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
Здесь звонящий просто звонит getProfile
и присоединяет функцию, которая говорит, что делать с возвращенными данными, и переходит.
Редактировать Если вы хотите обновить один и тот же объект, вы можете просто использовать похожий код, но вам нужно сохранить this
в какой-то другой переменной, потому что привязка this
происходит во время выполнения.
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;
};
Вот как promises
Работа.
Поскольку у вас есть асинхронная задача, которая занимает некоторое время, и JavaScript
это однопоточный язык, вы не хотите блокировать свой код и ждать завершения этой асинхронной операции - иначе никто бы не использовал JavaScript
!!
Ну так что ты делаешь? Вы создаете promise
и продолжайте свой код.
Вы добавляете обратные вызовы к этому promise
и когда обещание будет выполнено, ваши обратные вызовы будут вызваны.
Я не использовал when
библиотека, но то, что вы хотите сделать, это что-то вроде этого:
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;
console.log(data);
// the callback will invoke after the deferred object is resolved.
deferred.promise.then(function(o){ console.log('resolved!!!'); });
deferred.resolve(data);
}else{
deferred.reject('something bad occured');
return false;
}
});
return deferred.promise;
};
Старайтесь избегать использования отложенного шаблона ( см. Здесь).
Когда.js поддерживает шаблон "Выявление конструктора", это также приводит к более читабельному коду.
User.prototype.getProfile = function(criteria) {
var self = this;
var options = {
criteria: criteria,
select: 'name id email'
};
return when.promise(function(resolve, reject) {
self.User.load(options, function(err, data) {
if (err) {
reject(err);
}
self.name = data.name;
self.email = data.email;
self.id = data.id;
resolve(); // or resolve(data)
});
});
};
следующий
userObject.getProfile()
.then(function() {
// data loaded
})
.catch(function(err) {
// something went wrong, process the error
});