[英]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.