NodeJS中如何跨函数使用MySQL查询结果为MyPlan变量赋值
问题原因
你遇到的报错和值无法读取的问题核心是三点:
- 异步时序问题:Node.js中
MySQL.connect、MySQL.query都是异步非阻塞操作,代码不会等数据库返回结果就继续往下执行,查询结果返回前就读取变量,自然拿到undefined。 - 作用域问题:
results是forEach回调的形参,作用域仅局限在回调函数内部,外部函数、全局作用域都无法直接访问这个变量。 - this指向问题:
MySQL.query的回调是普通函数,严格模式下内部this为undefined,给this.myresult赋值会报错;直接给未声明的myresult赋值不符合变量作用域规则,会报未定义错误。
解决方案
用async/await改写异步逻辑,从根源上规避回调的作用域、时序问题,步骤如下:
- 将数据库连接、查询逻辑封装为Promise形式,用
await等待异步操作执行完成后再取结果 - 必须等数据库查询拿到
plan值之后,再启动startMyPlan里的定时器,避免提前读取空值 - 将查询到的plan值存在类实例属性上,供定时器回调读取
完整代码示例:
// 封装后的load函数,异步返回查询到的plan值 async function load() { const MySQL = SQL.createConnection(credentials); // 等待数据库连接完成 await new Promise((resolve, reject) => { MySQL.connect((err) => { if (err) { console.log(err); process.exit(0); } for (let i = 0; i < 250; i++) console.log('\n'); console.log('Successfully logged in!'); resolve(); }); }); // 等待查询完成返回结果 const rows = await new Promise((resolve, reject) => { MySQL.query("SELECT plan FROM users WHERE username = 'asd123'", (err, rows) => { if (err) { console.log(`[!] SQL Error: ${err}`); reject(err); return; } resolve(rows); }); }); // 单用户查询直接取第一条结果的plan字段即可,不需要循环forEach return rows[0].plan; }
对应类中的逻辑调整:
// 新增初始化方法,先查库拿值再启动定时任务 async init() { // 等待查询完成,把值存在实例属性上 this.MyPlan = await load(); // 拿到有效值后再启动计划 this.startMyPlan(); } startMyPlan() { this.botCountInt = setInterval(() => { const json = { connected: 0, MyPlan: this.MyPlan }; this.send(json); }, 100); }
启动逻辑调整:初始化类实例后,不要直接调用load()或者startMyPlan(),而是调用init()方法,保证执行时序正确。
不推荐继续用多层回调的写法:如果硬要用回调实现,需要在外层提前声明作用域足够的变量存结果、固定this指向、在查询回调内部再调用startMyPlan,代码嵌套深、可维护性差,很容易再出其他作用域bug。
内容的提问来源于stack exchange,提问作者Onyx
相关产品推荐
相关产品推荐

