SailsJS使用Bluebird Promises的Waterline

5

当使用Waterline ORM时,如果我想使用默认提供的bluebird promise api,我该如何将处理过程传递回控制器。

以下是代码:

module.exports = {
    //Authenticate
    auth: function (req, res) {
        user = req.allParams();
        //Authenticate
        User.authenticate(user, function (response) {
            console.log(response);
            if (response == true) {
                res.send('Authenticated');
            } else {
                res.send('Failed');
            }
        });
    }
};


module.exports = {
    // Attributes

    // Authenticate a user
    authenticate: function (req, cb) {
        User.findOne({
            username: req.username
        })
        .then(function (user) {
            var bcrypt = require('bcrypt');
            // check for the password
            bcrypt.compare(req.password, user.password, function (err, res) {
                console.log(res);
                if (res == true) {
                    cb(true);
                } else {
                    cb(false);
                }
            });
        })
        .catch(function (e) {
            console.log(e);
        });
    }
};

我只是想实现一个认证功能,业务逻辑很简单。我困惑的是请求流程如何返回到控制器。如果我尝试返回响应,承诺不会响应,但使用cb(value)可以。


在这段代码中,你在哪里返回Promise? - vanadium23
根据文档(http://sailsjs.org/#!/documentation/reference/waterline/queries),Waterline有Bluebird的部分实现,我在User.find....then之后的代码中感到困惑。 - Gayan Hewa
1个回答

6
与 Promise 一起工作的关键是永远不要中断链条。Promise 链条取决于每个步骤返回一个 Promise 或值,或抛出错误。
以下是您代码的重写。请注意:
- 路径中的每个回调都返回某些内容,每个函数都返回它所处理的 Promise 链条(即使是 `.auth()`;在某些情况下可能有用) - 我使用了 BlueBird 的 `.promisifyAll()` 使 `bcrypt` 与之搭配使用 - 我将 `authenticate()` 从请求/响应基础设施中分离,通过使 `username` 和 `password` 成为明确的参数来实现。这样可以更轻松地重复使用它。
现在我们有了以下代码(未经 100% 测试,我没有打扰安装 waterline):
module.exports = {
    // authenticate the login request
    auth: function (req, res) {
        var params = req.allParams();
        return User.authenticate(params.username, params.password)
        .then(function () {
            res.send('Authenticated');
        })
        .fail(function (reason) {
            res.send('Failed (' + reason + ')');
        });
    }
};

并且

var Promise = require("bluebird");
var bcrypt = Promise.promisifyAll(require('bcrypt'));

module.exports = {
    // check a username/password combination
    authenticate: function (username, password) {
        return User.findOne({
            username: username
        })
        .then(function (user) {
            return bcrypt.compareAsync(password, user.password)
        })
        .catch(function (err) {
            // catch any exception problem up to this point
            console.log("Serious problem during authentication", err);
            return false;
        })
        .then(function (result) {
            // turn `false` into an actual error and
            // send a less revealing error message to the client
            if (result === true) {
                return true;
            } else {
                throw new Error("username or password do not match");
            }
        });
    }
};

2
这解答了我很多关于 Promise 的疑问。+1 - Gayan Hewa
2
它们需要一些时间来适应,但之后它们是一个美妙的工具。与Node的本地回调架构相比,在各个方面都更好。 - Tomalak
这个函数是否应该返回一个 Promise 而不是 true/false 呢?否则在控制器或者 HTTP 层面就没有实际的回调可供使用,这样就会变成同步调用了。 - mkbrv
一个 Promise 不一定要返回一个 Promise。你可以直接返回一个值,这就是它的全部意义。我不太明白你所说的“否则就没有回调”的意思是什么? - Tomalak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接