我对NodeJS相当陌生,并试图理解异步,等待和承诺。如果我将resolve()置于'con.query'的回调范围之外(仍在新的Promise范围之内),则likes变量未定义。仅当resolve()在回调内部时才填充它。为什么会这样?范例:
//WORKS
async function findLikes(q, req, res){
var likes_q = `SELECT * FROM PublicStoryLike WHERE authorId =
${req.body.token_id}`;
var likes;
var lookup = {};
//const query = util.promisify(con.query).bind(con);
const query = new Promise((resolve, reject) => {
con.query(likes_q, (err, result) => {
likes = JSON.stringify(result);
resolve(); //INSIDE con.query
});
})
//DOESN'T WORK
async function findLikes(q, req, res){
var likes_q = `SELECT * FROM PublicStoryLike WHERE authorId =
${req.body.token_id}`;
var likes;
var lookup = {};
//const query = util.promisify(con.query).bind(con);
const query = new Promise((resolve, reject) => {
con.query(likes_q, (err, result) => {
likes = JSON.stringify(result);
});
resolve(); //OUTSIDE con.query
})
答案 0 :(得分:0)
第二个代码块中的问题是您正在立即兑现承诺。您不必等待con.query
方法完成。
由于您要使用async / await并且您似乎正在使用util.promisify
,因此我建议以下内容:
async function findLikes(q, req, res) {
const likes_q = `SELECT * FROM PublicStoryLike WHERE authorId = ${
req.body.token_id
}`;
const query = util.promisify(con.query).bind(con);
const likes = await query(likes_q);
// ....
}
您可以看到不需要手动创建Promise。这就是util.promisify
会为您做的。您只需为此await
。
编辑:通过进一步查看您的代码,我发现findLikes
就像一条明确的路线。通常,我不建议将Web请求逻辑与数据访问层结合使用。
我建议您通过使findLikes
为独立的异步函数来将它们分开:
async function findLikes(authorId) {
const likes_q = `SELECT * FROM PublicStoryLike WHERE authorId = ${
authorId
}`;
const query = util.promisify(con.query).bind(con);
return await query(likes_q);
}
然后在您的路线中:
async function findLikesRoute(q, req, res){
const likes = await findLikes(req.body.token_id);
//... work with the data
}
这将为您带来关注点分离的好处。例如,如果假设您要更改公开数据的方式,该怎么办?现在,您现在不希望通过GraphQL公开它,而不是通过这种明确的途径公开它?
如果您将数据访问逻辑分开,那将非常容易。
答案 1 :(得分:0)
让我们忘记诺言。误解与此处的回调有关:您的情况可以说明为:
function works(callback) {
setTimeout(function() {
console.log("inside timeout");
callback("result");
}, 1000);
}
function doesnt(callback) {
setTimeout(function() {
console.log("inside timeout");
}, 1000);
callback();
}
works(function(result) { console.log("called back"); });
在工作版本中,当调用内部回调时,您将回调外部回调,这意味着您的情况是从数据库到达的结果。
在非工作版本中,您直接回调回调,但是计时器(或数据库调用)尚未完成,因此结果还不存在。
通常不应使用全局变量,尤其是在涉及异步时。您的likes
变量将导致您(并且已经)引起您的头痛,只需将其完全删除即可。而是使用所需的值 resolve 承诺(或回调)。这样,您可以轻松检测到错误:
getResult(function(result) {
callback(result); // works, result is ready
});
callback(result); // does not work, throws an error
在您的情况下,它将是:
async function findLikes(q, req, res){
const query = `SELECT * FROM PublicStoryLike WHERE authorId = ${req.body.token_id}`;
return new Promise((resolve, reject) => {
con.query(query, (err, result) => {
if(err) reject(err) else resolve(result);
});
});
}
findLikes(/*...*/)
.then(likes => {
// Work with likes here!
});