Callback Function返回undefined问题:Node.js数据库查询代码求助
兄弟,你的问题核心是没搞懂异步操作的返回逻辑——你在conn.query的回调里return token,但这个return根本不会让queryDB函数返回值,更别说上层的searchAccessToken了。咱们一步步拆解问题,再给你修正方案:
问题出在哪?
1. queryDB函数的异步陷阱
conn.query是异步执行的,你在它的回调函数里写的return token,只是结束了这个回调函数本身,不会让queryDB返回任何值。而且queryDB函数本身没有任何顶层的return语句,所以它默认返回undefined。
这就导致searchAccessToken里的return callback(sql),实际上是return了queryDB(sql)的结果——也就是undefined,所以你的console.log自然输出undefined。
2. 同步调用异步函数的错误
你直接用console.log(searchAccessToken(name,queryDB))试图同步获取异步操作的结果,这本身就不符合异步代码的逻辑。异步操作的结果只能通过回调、Promise或者async/await来获取,不能直接同步return。
修正方案(回调版本)
咱们先把代码改成标准的回调风格,贴合你原来的写法:
第一步:修复queryDB,让它支持回调传递结果
function queryDB(sql, callback){ db(function(err, conn){ // 先处理数据库连接错误 if (err) { return callback(err); } conn.query(sql, function(err, results){ // 不管成功失败,一定要释放连接 conn.release(); if(err){ return callback(err); // 传递查询错误 } // 有结果就返回token,没结果返回空字符串 const token = results.length ? results[0].accessToken : ""; callback(null, token); }); }); }
第二步:调整searchAccessToken的逻辑
不需要return callback的结果,直接把回调传递给queryDB即可:
function searchAccessToken(emailAddress, callback){ // 注意:这里有SQL注入风险!后面会说怎么改 var sql = "SELECT accessToken FROM device WHERE email_address = '" + emailAddress + "'"; queryDB(sql, callback); }
第三步:正确调用并获取结果
不能直接console.log,要通过回调拿到异步结果:
searchAccessToken(name, function(err, token) { if (err) { console.error('查询失败:', err); return; } console.log('获取到的AccessToken:', token); });
额外提醒:SQL注入风险!
你现在直接把emailAddress拼接到SQL语句里,这是非常危险的,攻击者可以通过构造恶意邮箱地址来执行任意SQL语句。赶紧改成参数化查询:
修正searchAccessToken和queryDB支持参数化:
// searchAccessToken里用占位符?代替直接拼接 function searchAccessToken(emailAddress, callback){ var sql = "SELECT accessToken FROM device WHERE email_address = ?"; queryDB(sql, [emailAddress], callback); // 把参数作为数组传递 } // 调整queryDB支持参数 function queryDB(sql, params, callback){ // 兼容如果params是回调的情况(可选) if (typeof params === 'function') { callback = params; params = []; } db(function(err, conn){ if (err) { return callback(err); } // 把参数数组传给conn.query conn.query(sql, params, function(err, results){ conn.release(); if(err){ return callback(err); } const token = results.length ? results[0].accessToken : ""; callback(null, token); }); }); }
进阶:用Promise/async-await简化代码
如果你的Node.js版本支持,用Promise或者async/await会让异步代码更易读:
// 先把db包装成Promise const getConnection = () => { return new Promise((resolve, reject) => { pool.getConnection((err, conn) => { if (err) reject(err); else resolve(conn); }); }); }; // queryDB改成Promise版本 function queryDB(sql, params){ return getConnection().then(conn => { return new Promise((resolve, reject) => { conn.query(sql, params, (err, results) => { conn.release(); if (err) reject(err); else { const token = results.length ? results[0].accessToken : ""; resolve(token); } }); }); }); } // searchAccessToken也改成Promise function searchAccessToken(emailAddress){ const sql = "SELECT accessToken FROM device WHERE email_address = ?"; return queryDB(sql, [emailAddress]); } // 用async/await调用 async function getToken() { try { const token = await searchAccessToken(name); console.log('获取到的AccessToken:', token); } catch (err) { console.error('查询失败:', err); } } getToken();
这样代码逻辑更清晰,也避免了回调嵌套的问题。
内容的提问来源于stack exchange,提问作者jdotdoe

