简体   繁体   English

承诺链未按预期顺序执行

[英]Promise chain not executing in expected order

I'm trying to use a sequence of promises to authenticate a user name and password, but the promises seen to be resolving too early. 我正在尝试使用一系列承诺来验证用户名和密码,但看到的承诺过早解决。

I have two methods from two different files involved here. 我在这里涉及两个不同的文件有两种方法。

First, my controller, which picks up the request and invokes my model for the authentication. 首先,我的控制器,它接收请求并调用我的模型进行身份验证。 The model is supposed to return a promise that will have authentication results when it resolves. 该模型应该返回一个在结算时将具有身份验证结果的承诺。

Here is my controller: 这是我的控制器:

router.post('/api/auth-tokens', function (req, res, next) {
    var creds = {user: req.body.user, password: req.body.password};
    people.authenticate(creds)
    .then(function (result) {
      var status = result.valid ? 200: 401; 
      res.sendStatus(status);
    });
});

people is the lexically scoped model. people是词汇范围的模型。 Here is the current implementation of the method used above: 以下是上面使用的方法的当前实现:

var bluebird = require('bluebird');
var bcrypt   = require('bcrypt');
var compare  = bluebird.promisify(bcrypt.compare);

exports.authenticate = function (args) {
    var promise = orm.select({
        db: db,
        table: table,
        where: {id: args.user},
        qrm: 'one'
    });

    promise.catch(function (err) {
        var auth_info = { valid: false };
        return auth_info;
    });

    promise.then(function (user) {
        var promise = compare(args.password, user.hash)
        .then(function (same) {
            var auth_info = { valid: same, permissions: user.permissions };
            return auth_info;
        });
        return promise;
    });

    return promise;
};

orm returns a promise that will throw an error if the user doesn't exist, or resolve and yield the database row if the user was found. orm返回一个promise,如果用户不存在则会抛出错误,或者如果找到用户则解析并生成数据库行。 (That is why I have that promise.catch invocation in there. It's in case the user doesn't exist) (这就是为什么我在那里有promise.catch调用。以防用户不存在)

If the user does indeed exist, I want to invoke bcrypt.compare to compare the input to the hash contained in the database row. 如果用户确实存在,我想调用bcrypt.compare来比较输入到数据库行中包含的哈希。 When that finishes asynchronously, I want to resolve the promise chain and yield control back to the controller, returning the results object. 当异步完成时,我想解析promise链并将控制权返回给控制器,返回results对象。

The issue I'm having though is that the .then in my controller is being executed immediately with the results of the initial promise returned by the call to orm.select . 我有虽然问题是.then在我的控制器正在由调用返回的最初的承诺的结果立即执行orm.select Can anyone explain why this is happening and how I can fix it? 任何人都可以解释为什么会发生这种情况以及如何解决这个问题?

It's happening because you've hooked up that callback directly to the promise returned by orm.select . 这种情况正在发生,因为你已经将该回调直接连接到orm.select返回的orm.select Instead, you need to use the promise returned by then . 相反,你需要使用返回的承诺, then

This is one of the biggest key things about promises: then returns a new promise . 这是关于承诺的最重要的事情之一: then返回一个新的承诺 (So does catch .) If your handler function returns a promise (technically, any thenable ) from either then or catch , the new promise that then (or catch ) returns will resolve/reject based on the promise you return. catch也是如此。)如果你的处理函数从then或者catch返回一个promise(技术上,任何可能 ), then (或catch )返回的新promise将根据你返回的promise来解析/拒绝。 If your handler function returns a non-promise value, the new promise from then (or catch ) is resolved (not rejected) with that value. 如果您的处理函数返回一个非promise值, then使用该值解析(或不catch )来自then (或catch )的新promise。

So authenticate should probably look like this: 因此, authenticate应该看起来像这样:

exports.authenticate = function (args) {
    return orm.select({
        db: db,
        table: table,
        where: {id: args.user},
        qrm: 'one'
    })
    .then(function (user) {
        return compare(args.password, user.hash)
        .then(function (same) {
            var auth_info = { valid: same, permissions: user.permissions };
            return auth_info;
        });
    })
    .catch(function (err) {
        var auth_info = { valid: false };
        return auth_info;
    });
};

Note that the changes are both to your outer function and what you do in then . 请注意,更改既适用于您的外部功能,也适用于您then Also note that the code in your catch callback will be called whether it's the original promise from orm.select that was rejected, or the one from compare . 另请注意,将调用catch回调中的代码,无论它是orm.select中被拒绝的原始承诺,还是来自compare的原始承诺。

To see what's going on, compare this snippet with the one after: 要查看正在发生的情况,请将此代码段与之后的代码段进行比较:

 // Returning the original promise // Usually NOT what you want function foo() { var promise = new Promise(function(resolve) { console.log("Starting first promise"); setTimeout(function() { console.log("Resolving first promise"); resolve("first"); }, 500); }); promise.then(function() { promise = new Promise(function(resolve) { console.log("Starting second promise"); setTimeout(function() { console.log("Resolving second promise"); resolve("second"); }, 500); }); }); return promise; } foo().then(function(result) { console.log("Got result: " + result); }); 

Second: 第二:

 // Returning the original promise // Usually NOT what you want function foo() { return new Promise(function(resolve) { console.log("Starting first promise"); setTimeout(function() { console.log("Resolving first promise"); resolve("first"); }, 500); }) .then(function() { return new Promise(function(resolve) { console.log("Starting second promise"); setTimeout(function() { console.log("Resolving second promise"); resolve("second"); }, 500); }); }); } foo().then(function(result) { console.log("Got result: " + result); }); 

Your controller is executing on a different promise than the one which uses bcrypt.compare 您的控制器正在执行与使用bcrypt.compare的承诺不同的承诺

do it like so to ensure that the people.authenticate returns a promise chain which resolves to the inner result post-comparison: 这样做是为了确保people.authenticate返回一个promise链,它解析为内部结果后比较:

var promise = orm.select(/* ... */)
    .then(/* bcrypt usage here */)
    .catch(/* error handling here */);

return promise;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM