我正在使用Kris Kowal的 Q 库,使用控制器和存储库实现 Node.js 逻辑。我有一种感觉,我在下面的例子中使用promises的方式是不正确的。但我无法找到关于如何通过多个层或函数使用promises的正确模式的任何指导。
我做得对吗?实现这种逻辑的正确方法是什么?
//模块:存储库
exports.findOne = function (query) {
var deferred = Q.defer();
db.query(query, function (err, data) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
return deferred.promise;
};
//模块:用户
var isEmailAvailable = function (value) {
var deferred = Q.defer();
Repository.findOne({email: value})
.then(function (user) {
if (user) {
if (self.id === user.id) {
deferred.resolve(true);
}
else {
deferred.resolve(false);
}
} else {
deferred.resolve(true);
}
})
.fail(function (err) {
deferred.reject(err);
});
return deferred.promise;
};
this.save = function () {
var deferred = Q.defer();
isEmailAvailable(this.email)
.then(function (result) {
if (result) {
Repository.upsert(self)
.then(function (user) {
deferred.resolve(user); //--- Yey!!!
}).fail(function () {
deferred.reject('Account save error')
});
} else {
deferred.reject('The email is already in use');
}
}).fail(function () {
deferred.reject('Account validation error')
});
return deferred.promise;
};
答案 0 :(得分:3)
我觉得我使用promises的方式不正确
是的,你经常使用deferred antipattern。 Promises do chain,这意味着您只需return
值{甚至}来自then
回调的承诺,.then()
调用将产生对这些返回值的承诺。当你throw
时,结果承诺将被拒绝。
您在存储库模块中使用延迟是正确的,因为db.query
api需要promisified。但是用户模块可能会严重缩减,当您已经有承诺时,您不需要使用任何延迟。
function isEmailAvailable(value) {
return Repository.findOne({email: value})
.then(function (user) {
return !user || self.id === user.id;
});
}
this.save = function() {
return isEmailAvailable(this.email)
.then(function (result) {
if (result) {
return Repository.upsert(self)
.then(null, function(err) {
throw new Error('Account save error');
});
} else {
throw new Error('The email is already in use');
}
}, function(err) {
throw new Error('Account validation error');
});
};
或者,正如@ Roamer-1888所建议的那样,使用exceptions for control flow:
function isEmailAvailable(value) {
return Repository.findOne({email: value})
.then(function (user) {
if (user && self.id !== user.id)
throw new Error('The email is already in use');
}, function(err) {
throw new Error('Account validation error');
});
}
this.save = function() {
return isEmailAvailable(this.email)
.then(function () {
return Repository.upsert(self)
.then(null, function(err) {
throw new Error('Account save error');
});
});
};