You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复async函数中for循环内使用await的语法错误?

问题分析

你遇到的两个问题本质上是同一个原因:混用了回调式异步和async/await语法。

  1. 给con.query加await时报错,是因为await所在的回调函数(e, curr) => {...}没有被声明为async——await只能在async函数内部使用,而这个回调并不是async的。
  2. 先打印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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:06:20