我试图让async / await
按顺序触发事件,但似乎我错过了一些东西,因为我的console.log标记触发的顺序与我希望的顺序相反。
我想知道是否与我在users.js
中使用嵌套函数有关,但尝试了async / await
的多种变体,它始终无法按预期工作。
// index.js
var users = require("./users.js");
app.post("/getToken", async function(req, res) {
if (req.body.email && req.body.password) {
const email = req.body.email;
const password = req.body.password;
const user = await users(email, password)
// running this should output console.log("No 1")
// from users.js first, but doesn't ?
console.log('No 2')
if (user) {
var payload = {
id: user.id
};
var token = jwt.encode(payload, cfg.jwtSecret);
res.json({
token: token
});
} else {
res.sendStatus(401);
}
} else {
res.sendStatus(401);
}
});
// users.js
module.exports = function(emailAddress, password) {
db.connect();
var query = `
SELECT
id,
email,
password,
salt
FROM
users
WHERE
email = ?`;
var query_params = [emailAddress];
db.query(
query,
query_params,
function(error, result, fields) {
console.log('No 1')
if (error) throw error;
if ( result.length == 1 ) {
if ( checkPass(password, result[0].password, result[0].salt ) ) {
return { id: result[0].id }
} else {
console.log("login False | Password");
return false;
}
} else {
console.log("login False | username");
return false;
}
}
)
}
答案 0 :(得分:4)
您的users.js
功能无法返回任何内容。您通过query
的回调会做,但整体功能不会。由于它永远不会明确返回任何内容,因此调用它的结果是undefined
。如果您await
undefined
,它就像await Promise.resolve(undefined)
一样,因此很快就会调用您的解析处理程序。
您希望该函数返回一个在工作完成之前无法解决的承诺。由于它使用的是旧式Node callbck API,因此使用new Promise
来创建该承诺是合理的(或者,为该DB获取或创建启用了promise的API)。
我还怀疑你错误地调用了connect
,因为通常情况下这是异步操作,但是你将它视为同步。
见评论:
users.js
module.exports = function(emailAddress, password) {
return new Promise((resolve, reject) => {
// Use the callback to know when the connection is established
db.connect(error => {
if (error) {
// Connection failed
reject(error);
return;
}
var query = `
SELECT
id,
email,
password,
salt
FROM
users
WHERE
email = ?`;
var query_params = [emailAddress];
db.query(
query,
query_params,
function(error, result, fields) {
// Throwing an error here does nothing useful. Instead,
// reject the promise.
if (error) {
reject(error);
return;
}
// Resolve our promise based on what we got
if ( result.length == 1 ) {
if ( checkPass(password, result[0].password, result[0].salt ) ) {
resolve({ id: result[0].id });
} else {
console.log("login False | Password");
resolve(false);
}
} else {
console.log("login False | username");
resolve(false);
}
}
);
});
});
}
然后使用它:
app.post("/getToken", async function(req, res) {
// You must handle errors, since `post` won't do anything with the return
// value of this function
try {
if (req.body.email && req.body.password) {
const email = req.body.email;
const password = req.body.password;
// Now this waits here, since `users` returns a promise that
// isn't resolved until the query completes
const user = await users(email, password)
console.log('No 2')
if (user) {
var payload = {
id: user.id
};
var token = jwt.encode(payload, cfg.jwtSecret);
res.json({
token: token
});
} else {
res.sendStatus(401);
}
} else {
res.sendStatus(401);
}
} catch (e) {
res.sendStatus(401);
}
});
答案 1 :(得分:3)
问题是db.query
函数是异步的 - 您提供的是在数据库调用完成时执行的回调函数。您可能需要在Promise中包装整个函数:
module.exports = function(emailAddress, password) {
return new Promise(function(resolve, reject) {
db.connect();
var query = `
SELECT
id,
email,
password,
salt
FROM
users
WHERE
email = ?`;
var query_params = [emailAddress];
db.query(
query,
query_params,
function(error, result, fields) {
if (error) return reject(error)
if ( result.length == 1 ) {
if ( checkPass(password, result[0].password, result[0].salt ) ) {
resolve({id: result[0].id})
} else {
console.log("login False | Password");
reject();
}
} else {
console.log("login False | username");
reject();
}
}
)
})
}
您可以详细了解Promise API here
编辑:
所以你应该另外让connect
同步。这是我为你重构的一段代码。它应该工作得很好。我使用了一些ES6元素使其更具可读性。
const connect = () => new Promise((resolve, reject) => {
db.connect((err) => {
if (err) return reject(err);
resolve();
})
})
const makeDbRequest = (emailAddress, password) => new Promise((resolve, reject) => {
const query = `
SELECT
id,
email,
password,
salt
FROM
users
WHERE
email = ?`;
const query_params = [emailAddress];
db.query(
query,
query_params,
handleDbData(resolve, reject, password),
);
})
const handleDbData = (resolve, reject, password) => (error, result, fields) => {
if (error) return reject(error)
if ( result.length == 1 ) {
if ( checkPass(password, result[0].password, result[0].salt ) ) {
resolve({id: result[0].id})
} else {
console.log("login False | Password");
reject();
}
} else {
console.log("login False | username");
reject();
}
}
module.exports = (emailAddress, password) => new Promise((resolve, reject) => {
connect()
.then(() => {
makeDbRequest(emailAddress, password)
.then(resolve)
.catch(reject)
})
.catch(reject);
})