在模块之间共享承诺与具有多个承诺

时间:2015-03-03 23:36:31

标签: javascript node.js promise repository-pattern q

我正在使用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;
};

1 个答案:

答案 0 :(得分:3)

  

我觉得我使用promises的方式不正确

是的,你经常使用deferred antipatternPromises 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');
        });
    });
};