在node项目中使用mysql包时,我遇到一个select出来的结果无法同步到主线程的问题。具体来说是这样的,我把sql相关的操作封装在几个js文件中,比如说与tag相关的crud操作,就放在TagHelper.js中,然后在router.js中,配置路由时根据具体的业务去调用helpers。在TagHelper.js中,我封装的select方法无法返回正确的结果集,之前的方法代码如下
function getAll() {
let res = [];
const sqlStr = "select id,name from tag";
db.query(sqlStr,(err,results)=>{
if (err) {
console.log(err.message);
return;
}
//拷贝一个results给res
res = results.concat();
})
return res;
}
db是通过mysql.createPool方法创建的。其query方法第二个参数是结果返回的回调函数,这意味着这个回调是一个异步回调,它会等待mysql查询完毕返回结果后再执行,所以node在执行query时就做了两件事:传入了sql字符串和指定了回调,然后就返回空数组res了。那么我们该怎么让query方法等待结果集返回呢?
这里需要用到async/await的知识,详情可以看我写的这篇文章
大致理解了async/await后,你就大概知道怎么做了
async function getAll() {
let res = [];
const sqlStr = "select id,name from tag";
let select = function (err, result) {
if (err) {
console.log(err.message);
return;
}
res = result.concat();
// console.log('已赋值');
};
//await会等待promise改变状态
await new Promise((resolve)=>{
db.query(sqlStr, select)
//end的回调应该是在select回调之后执行的,所以这里resolve可以理解
.on('end', function() {
resolve()
});
})
return res;
}
在router.js中,需要将router的路由方法回调前面加上async修饰,并且里面相关的select方法需要加上await修饰,如:
router.get("/alltags", async function (req, res, next) {
try {
const allTags = await tagHelper.getAll();
const allTagList = allTags.map((val) => {
return val["name"];
});
// console.log(allTagList);
res.status(200).json(allTagList);
} catch (err) {
res.statusCode = 500;
res.statusMessage = "server internal error";
res.send("error");
}
});
事实上,在没有理解js的async和await之前,我有一些C#的async/await经验,所以尝试着解决了下,但无法很好地去解释它,所以通过我学习promise并对promise做一些笔记,那么我相信这些笔记可以帮助你更好地去理解以及去阐述其中的“为什么”了。