Node.js中connection.query回调内return失效如何正确返回查询结果
问题原因
你遇到的是JavaScript异步回调的经典作用域&执行时序问题,核心原因是connection.query是异步非阻塞API,回调函数的返回值不会成为外层函数的返回值,且外层函数不会等待异步查询执行完成就会提前返回。
根因细节
connection.query传入的回调函数不会在调用query时立刻执行,会等SQL查询完成后才被放入事件队列等待调度,这个过程不会阻塞外层同步代码的执行- 回调内部写的
return "A",作用域仅属于回调函数本身,和外层getID函数的返回值没有任何关系 - 外层
getID调用query后,会立刻执行下一行同步代码return "B",此时异步查询还没完成,函数就已经返回了"B" - 你贴出的运行结果中没有
console.log(rows)的打印内容,也能证明回调函数在getID返回"B"时还未执行,时序上晚于外层函数的返回动作 - 代码存在笔误:定义的函数名为
getID,调用时写的是getCredit(),正常运行会直接抛出未定义错误 - 原回调内写的
throw err无法被外层捕获,因为回调执行时外层getID的执行栈已经退出,错误会被抛到全局
修复方案
把异步回调逻辑包装为Promise,配合async/await语法拿到异步执行的结果,参考代码如下:
async function getID(){ const sql = 'SELECT * from id' // 包装回调为Promise,等待异步查询完成 const result = await new Promise((resolve, reject) => { connection.query(sql, (err, rows) => { if (err) return reject(err); console.log(rows) // 把需要返回的结果通过resolve传出 resolve("A") // 实际业务中直接返回查询结果即可:resolve(rows) }) }) // 异步操作完成后,把结果作为函数返回值 return result } // 修正函数名笔误 const list = getID(); list.then(res => console.log(res)); // 注意:这里直接打印list会得到pending状态的Promise,因为异步操作还没执行完成 console.log(list)
如果使用的是mysql2这类支持Promise调用的数据库驱动,可以直接用内置的promise方法,不用手动包装:
async function getID(){ const sql = 'SELECT * from id' const [rows] = await connection.promise().query(sql); console.log(rows); return "A"; }
补充说明
- 所有async函数的返回值永远是Promise对象,必须通过
await或者.then()的方式才能拿到最终的执行结果,不要在同步代码流里直接读取async函数的返回值 - 异步回调风格的API如果要配合async/await使用,必须先包装为Promise形式,把结果通过resolve、错误通过reject传出,才能正常被await捕获
内容的提问来源于stack exchange,提问作者gagore
相关产品推荐
相关产品推荐

