NodeJS中如何将SQL查询结果返回到父函数作用域?
解决Brackets扩展中NodeJS查询结果无法传递到父作用域的问题
我正在开发一款Brackets文本编辑器扩展,用来把工作时长存储到数据库并查看时间记录。目前用NodeJS和SQL服务器交互,已经实现了时长录入和SELECT查询,但就是没法把查询结果传递到父函数作用域里传给main.js。我是NodeJS新手,试过回调和Promise但没搞定。现在的情况是,我想让viewTime()函数以Promise形式返回给main.js,要是能把con.connect()改成普通函数,就能通过registerCommand在main.js里调用了。我的代码如下:
(function () { "use strict"; var mysql = require('mysql'); /** * @private * * @return {array} */ function viewTime() { var con = mysql.createConnection({ host: "localhost", user: "root", password: "root", database: "brackets_timer_data" }); con.connect(function(err) { if (err) { console.log(err); } else { console.log("Connected!"); } con.query("SELECT * FROM work_sessions", function (err, result, fields) { if (err) { console.log(err); } //I need to get the result from here }); }); //And return it here so I can pass the variable to main.js } /** * Initializes the test domain with several test commands. * @param {DomainManager} domainManager The DomainManager for the server */ function init(domainManager) { if (!domainManager.hasDomain("view")) { domainManager.registerDomain("view", {major: 0, minor: 1}); } domainManager.registerCommand( "view", // domain name "viewTime", // command name viewTime, // command handler function false, // this command is synchronous in Node "Returns time entry results.", [{}], [{name: "results", // return values type: "array", description: "Time entry results"}] ); } exports.init = init; }());
核心问题分析
你遇到的问题本质是异步操作的结果无法同步返回——con.connect()和con.query()都是异步回调式的,你的viewTime()函数会在数据库操作完成前就执行到末尾,自然返回不了结果。要解决这个,必须把异步操作封装成Promise,同时告诉Brackets的DomainManager这个命令是异步的。
修改后的完整代码
(function () { "use strict"; var mysql = require('mysql'); /** * @private * @return {Promise<array>} 返回包含时间记录的Promise */ function viewTime() { // 用Promise包装整个异步流程 return new Promise((resolve, reject) => { var con = mysql.createConnection({ host: "localhost", user: "root", password: "root", database: "brackets_timer_data" }); con.connect(function(err) { if (err) { console.log(err); reject(err); // 连接失败时拒绝Promise,传递错误 return; } console.log("Connected!"); con.query("SELECT * FROM work_sessions", function (err, result, fields) { // 无论成功失败,都要关闭数据库连接,避免资源泄漏 con.end(); if (err) { console.log(err); reject(err); // 查询失败时拒绝Promise return; } resolve(result); // 查询成功时,把结果传给Promise的resolve }); }); }); } /** * Initializes the test domain with several test commands. * @param {DomainManager} domainManager The DomainManager for the server */ function init(domainManager) { if (!domainManager.hasDomain("view")) { domainManager.registerDomain("view", {major: 0, minor: 1}); } domainManager.registerCommand( "view", // domain name "viewTime", // command name viewTime, // command handler function true, // 这里改成true!告诉DomainManager这是异步命令(返回Promise) "Returns time entry results.", [], // 空参数列表简化写法 [{name: "results", // return values type: "array", description: "Time entry results"}] ); } exports.init = init; }());
关键修改点说明
用Promise封装异步操作:
- 把
viewTime()改成返回Promise,用resolve(result)传递查询结果,用reject(err)传递错误。这样调用者可以通过.then()或await获取结果。 - 每次查询完成后调用
con.end()关闭连接,防止数据库连接泄漏。
- 把
修改DomainManager注册配置:
- 把
registerCommand的第四个参数(同步/异步标识)从false改成true,因为现在viewTime()返回Promise,属于异步命令,Brackets需要知道这一点才能正确处理返回值。
- 把
在main.js中的调用方式
现在你可以在main.js里用异步方式调用这个命令了,比如:
// 假设你已经获取了domain对象 async function loadTimeRecords() { try { const timeResults = await brackets.app.domains.view.viewTime(); // 拿到结果后做你需要的处理,比如渲染到UI上 console.log("时间记录:", timeResults); } catch (error) { console.error("加载时间记录失败:", error); } } // 调用函数加载记录 loadTimeRecords();
这样就能顺利把数据库查询结果从Node层传递到Brackets的前端main.js里了!
内容的提问来源于stack exchange,提问作者Isaac Dew
相关产品推荐
相关产品推荐

