【新手求助】Nodejs 异步操作问题

发布于 1周前 作者 nodeper 来自 nodejs/Nestjs

【新手求助】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;
        });
}

请问如何正确的实现这个功能啊


4 回复

要解决这个问题,我们需要理解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);

解释

  1. getDeptList 函数:

    • 这个函数接受一个deptid参数,并查询所有子部门。
    • 使用Promise来处理异步查询结果。
    • 使用await来等待子部门查询完成,并递归调用getDeptList获取子部门的子部门。
  2. 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.如果你的部门嵌套很深有多级怎么办,你这里只有两级 如果把这两种情况考虑进去,你再设计下你的查询看看

可以用wind.js用同步思维写异步代码

要正确地实现这个功能,你需要使用异步编程的方法,比如使用回调函数、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/awaitPromise 来处理异步操作,避免了回调地狱,并使得逻辑更加清晰。它首先获取顶层部门列表,然后递归地获取每个部门的子部门列表。最后,将所有数据组合成期望的格式输出。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!