【新手求助】Nodejs 异步操作问题
【新手求助】Nodejs 异步操作问题
数据库表um_department:
CREATE TABLE `um_department` (
`deptid` int(11) NOT NULL AUTO_INCREMENT, //部门id
`dept` varchar(64) NOT NULL DEFAULT '', //部门名字
`dupid` int(11) DEFAULT '0', //上级部门id,dupid=0表示此部门为顶级部门
`deptshow` varchar(127) DEFAULT '', //部门信息
PRIMARY KEY (`deptid`)
) ENGINE=MyISAM AUTO_INCREMENT=74 DEFAULT CHARSET=gbk;
现在要查出整个部门树的结构,返回下面这样的数据
[{deptid:1, dept: '部门1', dupid:0, deptshow: '', deptlist: [{deptid:2, dept: '部门2', dupid:1, deptshow: ''}, {deptid:3, dept: '部门3', dupid:1, deptshow: ''}]}]
用的mysql数据查询模块是nodejs-mysql-native,我发现我写的时候还是同步的思维,不正确,代码如下:
var deptlist = [];
db.query("SELECT * from um_department where dupid='0'")
.on("row", function(r) {
r.deptlist = getDeptList(r.deptid);
deptlist.push(r);
})
.on("end", function(r) {
console.log(deptlist);
});
function getDeptList(deptid) {
var deptlist = [];
db.query("SELECT * from um_department where dupid = '" + deptid + "'")
.on("row", function(r) {
r.deptlist = getDeptList(r.deptid);
deptlist.push(r);
})
.on("end", function(r) {
return deptlist;
});
}
请问如何正确的实现这个功能啊
要解决这个问题,我们需要理解Node.js中的异步编程模型。在Node.js中,很多操作都是异步的,比如数据库查询。直接使用同步思维会导致回调地狱(Callback Hell)或者无法得到预期的结果。
正确的实现方法
我们可以使用Promise来处理异步操作,这样可以更好地组织代码逻辑。这里我们使用async/await
语法来简化异步代码的编写。
首先,确保你已经安装了mysql-native
库:
npm install mysql-native
然后,你可以按照以下方式修改你的代码:
const mysql = require('mysql-native');
const db = mysql.createConnection({
user: 'your_username',
password: 'your_password',
database: 'your_database'
});
// 获取部门列表的函数
async function getDeptList(deptid) {
const rows = await new Promise((resolve, reject) => {
db.query(`SELECT * FROM um_department WHERE dupid = ?`, [deptid], (err, rows) => {
if (err) reject(err);
resolve(rows);
});
});
const deptChildren = await Promise.all(rows.map(async row => ({
...row,
deptlist: await getDeptList(row.deptid)
})));
return deptChildren;
}
// 主函数
async function main() {
const topDepts = await new Promise((resolve, reject) => {
db.query(`SELECT * FROM um_department WHERE dupid = 0`, (err, rows) => {
if (err) reject(err);
resolve(rows);
});
});
const deptTree = await Promise.all(topDepts.map(async dept => ({
...dept,
deptlist: await getDeptList(dept.deptid)
})));
console.log(deptTree);
}
main().catch(console.error);
解释
-
getDeptList
函数:- 这个函数接受一个
deptid
参数,并查询所有子部门。 - 使用
Promise
来处理异步查询结果。 - 使用
await
来等待子部门查询完成,并递归调用getDeptList
获取子部门的子部门。
- 这个函数接受一个
-
main
函数:- 查询顶级部门。
- 对每个顶级部门,递归地获取其所有子部门,构建完整的部门树结构。
- 使用
await
来确保所有的异步操作都已完成。
通过这种方式,我们能够以一种更清晰、更易于维护的方式来处理复杂的异步操作。
当然不行拉,一定要用异步的思维。 将异步的函数嵌套在异步函数中,例如
db.select('xxxxxx').exec(function(err,doc){
//查询出最高级部门doc
db.select('根据doc查出其下子部门').exec(function(err,docs){
doc.list = docs;
console.dir(doc);
});
});
这只是一个简单的例子,不是用的mysql模块,大概意思就是让你嵌套。 另外你这个数据库设计和查询有2个你思考一下: 1.如果你的顶级部门很多怎么办,你这里只是查的一个 2.如果你的部门嵌套很深有多级怎么办,你这里只有两级 如果把这两种情况考虑进去,你再设计下你的查询看看
要正确地实现这个功能,你需要使用异步编程的方法,比如使用回调函数、Promise 或者 async/await。这里提供一个使用 async/await 的解决方案,它可以让代码更易读且更容易理解。
首先确保你已经安装了 mysql
模块(如果你使用的是 nodejs-mysql-native
,可能需要查看文档确认其API):
npm install mysql
然后可以使用以下代码来实现你的需求:
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'yourusername',
password: 'yourpassword',
database: 'yourdatabase'
});
async function getDeptList(deptid) {
const [rows] = await new Promise((resolve, reject) => {
connection.query("SELECT * FROM um_department WHERE dupid = ?", [deptid], (err, rows) => {
if (err) return reject(err);
resolve(rows);
});
});
const deptlist = await Promise.all(rows.map(async (r) => ({
...r,
deptlist: await getDeptList(r.deptid)
})));
return deptlist.filter(r => r.deptlist.length > 0).length > 0 ? deptlist : rows;
}
async function main() {
const [topLevelRows] = await new Promise((resolve, reject) => {
connection.query("SELECT * FROM um_department WHERE dupid = 0", (err, rows) => {
if (err) return reject(err);
resolve(rows);
});
});
const result = await Promise.all(topLevelRows.map(async (r) => ({
...r,
deptlist: await getDeptList(r.deptid)
})));
console.log(result);
}
main().catch(console.error);
connection.end();
这段代码使用了 async/await
和 Promise
来处理异步操作,避免了回调地狱,并使得逻辑更加清晰。它首先获取顶层部门列表,然后递归地获取每个部门的子部门列表。最后,将所有数据组合成期望的格式输出。