如何修复async函数中for循环内使用await的语法错误?
问题分析
你遇到的两个问题本质上是同一个原因:混用了回调式异步和async/await语法。
- 给
con.query加await时报错,是因为await所在的回调函数(e, curr) => {...}没有被声明为async——await只能在async函数内部使用,而这个回调并不是async的。 - 先打印
maxid再输出maxID,是因为con.query是异步执行的,回调里的代码会在后续事件循环中运行,主线程会直接往下执行console.log("maxid" + maxID),此时maxID还没被赋值。
解决方案
要解决这个问题,我们需要把回调式的数据库查询转换成Promise形式,这样就能用async/await完全控制异步流程。
步骤1:将con.query包装为Promise
先写一个工具函数,把回调风格的查询转换成返回Promise的函数,这样就能用await等待结果:
// 封装Promise版的查询函数 function query(con, sql, params = []) { return new Promise((resolve, reject) => { con.query(sql, params, (err, results) => { if (err) reject(err); else resolve(results); }); }); }
如果你用的是
mysql2库,可以直接引入mysql2/promise,它自带Promise支持,不用自己封装。
步骤2:重构savePosition函数
把所有回调替换成await调用,确保每一步异步操作完成后再执行下一步:
async function savePosition(con) { const processedIDs = new Set(); // 用Set存储已处理的ID,效率更高 // 1. 先获取所有Callers数据,等待查询完成 const callers = await query(con, `SELECT * FROM Callers;`); if (callers.length < 1) throw new Error('No callers found'); for (let i = 0; i < callers.length; i++) { let maxCalls = -1; let maxID = ""; for (let j = 0; j < callers.length; j++) { const uID = callers[j].id; // 跳过已处理的ID if (processedIDs.has(uID)) continue; // 2. 等待当前用户的查询结果返回 const curr = await query(con, `SELECT * FROM Callers WHERE id = ?;`, [uID]); if (Number(curr[0].calls) > maxCalls) { maxID = curr[0].id; console.log(maxID); maxCalls = curr[0].calls; } } processedIDs.add(maxID); // 标记为已处理 console.log("maxid" + maxID); // 3. 等待更新操作完成 await query(con, `UPDATE Callers SET position = ? WHERE id = ?;`, [i + 1, maxID]); } }
步骤3:关键优化说明
- SQL注入防护:把直接拼接SQL的写法改成了参数化查询(用
?占位符),这能有效避免SQL注入攻击,是数据库操作的最佳实践。 - 用Set替代数组检查重复:
Set.has()的时间复杂度是O(1),比数组的includes()更高效,适合处理重复ID的检查。 - 全程异步控制:所有数据库操作都用
await等待完成,确保了代码执行顺序符合预期——先拿到maxID,再打印和更新数据库。
步骤4:调用时处理异常
因为savePosition是async函数,调用它时需要用try/catch捕获可能的错误:
// 在bot.js的调用处修改为async函数 jsFiles.forEach(async (file) => { try { const properties = require(`./cmds/${file}`); // 假设你在这里调用savePosition,记得传入数据库连接参数 // await savePosition(yourDatabaseConnection); } catch (err) { console.error('Error executing command:', err); } });
这样修改后,你的代码就能先拿到maxID的值,再执行后续的打印和更新操作,也不会再出现await的语法错误了。
内容的提问来源于stack exchange,提问作者Lolization
相关产品推荐
相关产品推荐

