簡體   English   中英

承諾鏈未按預期順序執行

[英]Promise chain not executing in expected order

我正在嘗試使用一系列承諾來驗證用戶名和密碼,但看到的承諾過早解決。

我在這里涉及兩個不同的文件有兩種方法。

首先,我的控制器,它接收請求並調用我的模型進行身份驗證。 該模型應該返回一個在結算時將具有身份驗證結果的承諾。

這是我的控制器:

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是詞匯范圍的模型。 以下是上面使用的方法的當前實現:

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返回一個promise,如果用戶不存在則會拋出錯誤,或者如果找到用戶則解析並生成數據庫行。 (這就是為什么我在那里有promise.catch調用。以防用戶不存在)

如果用戶確實存在,我想調用bcrypt.compare來比較輸入到數據庫行中包含的哈希。 當異步完成時,我想解析promise鏈並將控制權返回給控制器,返回results對象。

我有雖然問題是.then在我的控制器正在由調用返回的最初的承諾的結果立即執行orm.select 任何人都可以解釋為什么會發生這種情況以及如何解決這個問題?

這種情況正在發生,因為你已經將該回調直接連接到orm.select返回的orm.select 相反,你需要使用返回的承諾, then

這是關於承諾的最重要的事情之一: then返回一個新的承諾 catch也是如此。)如果你的處理函數從then或者catch返回一個promise(技術上,任何可能 ), then (或catch )返回的新promise將根據你返回的promise來解析/拒絕。 如果您的處理函數返回一個非promise值, then使用該值解析(或不catch )來自then (或catch )的新promise。

因此, 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;
    });
};

請注意,更改既適用於您的外部功能,也適用於您then 另請注意,將調用catch回調中的代碼,無論它是orm.select中被拒絕的原始承諾,還是來自compare的原始承諾。

要查看正在發生的情況,請將此代碼段與之后的代碼段進行比較:

 // 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); }); 

第二:

 // 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); }); 

您的控制器正在執行與使用bcrypt.compare的承諾不同的承諾

這樣做是為了確保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