NodeJS应用数据库查询返回数组为undefined问题求助
NodeJS数据库查询返回undefined问题解决方案
问题原因
你怀疑的点完全正确——异步操作的执行顺序导致了这个问题。
JavaScript里的数据库查询(比如mysql库的query方法)是异步操作:调用dbc.query后,函数会立刻继续执行后续代码,不会等待数据库返回结果。你的getSubData函数里,回调函数里的return rows根本不会作为getSubData的返回值,因为getSubData在数据库查询完成前就已经执行完毕,默认返回undefined。所以在getData里调用getSubData()时,拿到的是undefined,自然会触发Cannot read property 'length' of undefined的错误。
解决方案
用Promise + async/await改造代码,让异步操作的执行顺序符合你的预期:
1. 封装数据库查询为Promise
先把异步的query方法包装成返回Promise的函数,这样就能用await等待结果:
// themod.js const dbc = require('./mods/db.js'); // 封装查询操作,返回Promise const runQuery = (sql) => { return new Promise((resolve, reject) => { dbc.query(sql, (err, rows) => { if (err) { reject(err); } else { resolve(rows); } }); }); }; module.exports = { // 标记为异步函数 async getData() { try { // 等待第一个查询完成 const mainRows = await runQuery(` SELECT 1 rn, 'One' rt UNION SELECT 2 rn, 'Two' rt UNION SELECT 3 rn, 'Three' rt ; `); // 等待getSubData的查询完成,拿到结果 const subRows = await this.getSubData(); console.log('subRows.length: ', subRows.length); // 输出3 } catch (err) { console.log('主查询错误: ', err); } }, async getSubData() { try { const rows = await runQuery(` SELECT 10 rn, 'Ten' rt UNION SELECT 20 rn, 'Twenty' rt UNION SELECT 30 rn, 'Thirty' rt ; `); console.log('子查询结果长度: ', rows.length); // 输出3 return rows; // 这里返回的会被Promise包装,await能拿到值 } catch (err) { console.log('子查询错误: ', err); throw err; // 抛出错误让上层处理 } } };
2. 修改入口文件(可选,处理全局错误)
// theapp.js const tm = require('./themod.js'); // 调用异步函数,捕获可能的全局错误 tm.getData().catch(err => console.error('全局错误:', err));
可选优化:改用mysql2库(原生支持Promise)
如果可以更换依赖库,mysql2原生支持Promise API,不用自己封装查询:
- 安装依赖:
npm install mysql2 - 修改数据库连接文件:
// mods/db.js const mysql = require('mysql2/promise'); // 创建连接(返回Promise) const dbConn = mysql.createConnection({ host: 'localhost', user: 'unam', password: 'pwrd', database: 'dbname' }); module.exports = dbConn;
- 简化themod.js的查询逻辑:
// themod.js const dbConnPromise = require('./mods/db.js'); module.exports = { async getData() { try { const dbConn = await dbConnPromise; const [mainRows] = await dbConn.query(` SELECT 1 rn, 'One' rt UNION SELECT 2 rn, 'Two' rt UNION SELECT 3 rn, 'Three' rt ; `); const subRows = await this.getSubData(); console.log('subRows.length: ', subRows.length); } catch (err) { console.log('主查询错误: ', err); } }, async getSubData() { try { const dbConn = await dbConnPromise; const [rows] = await dbConn.query(` SELECT 10 rn, 'Ten' rt UNION SELECT 20 rn, 'Twenty' rt UNION SELECT 30 rn, 'Thirty' rt ; `); console.log('子查询结果长度: ', rows.length); return rows; } catch (err) { console.log('子查询错误: ', err); throw err; } } };
关键知识点说明
- Promise:把异步操作转化为可以等待的对象,成功时用
resolve返回结果,失败时用reject返回错误。 - async/await:
async标记的函数会返回Promise,await只能在async函数里使用,它会暂停函数执行,直到Promise完成后再继续。 - 原来的回调函数里的
return无法作为外层函数的返回值,因为外层函数已经先执行完毕了;用Promise+await可以让我们正确拿到异步操作的结果。
内容的提问来源于stack exchange,提问作者TenG
相关产品推荐
相关产品推荐

