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

Node.js中for循环执行函数仅使用最后一个key的问题求助

解决循环中异步回调共享变量的问题

这是典型的闭包异步陷阱,我来帮你理清问题根源并给出修复方案:

问题原因

你用var声明的PItem和key是函数级作用域变量,而con.query是异步操作——当回调函数真正执行的时候,外层的for循环已经全部跑完了,此时PItem已经被更新为循环的最后一个key值,所以所有回调都会用这个最后值来执行SQL。

修复方案

方案1:用let替换var(最简洁)

let是块级作用域,每次循环会创建一个新的变量绑定,确保每个回调拿到的都是当前循环的key对应的PItem:

/*Global variable*/ 
let PItem = "Item"; 
for(let key in Prices){ // 这里改用let声明key
  PItem = key;
  let sql = `SELECT EXISTS(SELECT * FROM \`items\` WHERE \`name\` = "${PItem}")`;
  con.query(sql , function(err, result){
    if(err) return console.log(err);
    let result2 = 0; // 建议用let声明,避免全局污染
    for (var key6 in result){
      for(var key7 in result[key6])
        result2 = result[key6][key7];
    }
    if(result2 == 0){
      let sql = `INSERT INTO \`items\` (\`name\`, \`buy\`, \`sell\`, \`stock\`, \`maxStock\`) VALUES ("${PItem}", ${Prices[PItem].buy}, ${Prices[PItem].sell}, ${Prices[PItem].stock}, ${Prices[PItem].maxstock})`;
      con.query(sql, function(err, result){
        if(err) return console.log(err);
      });
    }
  });
}

方案2:用立即执行函数(IIFE)捕获当前变量

通过IIFE创建独立作用域,把当前循环的PItem传递进去,确保回调使用的是当前迭代的变量:

/*Global variable*/ 
var PItem = "Item"; 
for(var key in Prices){ 
  PItem = key;
  // 用IIFE捕获当前的PItem
  (function(currentItem) {
    var sql = 'SELECT EXISTS(SELECT * FROM `items` WHERE `name` = "'+currentItem+'")';
    con.query(sql , function(err, result){
      if(err) return console.log(err);
      let result2 = 0;
      for (var key6 in result){
        for(var key7 in result[key6])
          result2 = result[key6][key7];
      }
      if(result2 == 0){
        var sql = 'INSERT INTO `items` (`name`, `buy`, `sell`, `stock`, `maxStock`) VALUES ("'+currentItem+'", '+Prices[currentItem].buy+', '+Prices[currentItem].sell+', '+Prices[currentItem].stock+', '+Prices[currentItem].maxstock+')';
        con.query(sql, function(err, result){
          if(err) return console.log(err);
        });
      }
    });
  })(PItem);
}

方案3:改用forEach循环

forEach的每次迭代都会生成独立作用域,天然避免闭包共享变量的问题:

/*Global variable*/ 
let PItem = "Item"; 
// 遍历Prices的键数组
Object.keys(Prices).forEach(key => {
  PItem = key;
  let sql = `SELECT EXISTS(SELECT * FROM \`items\` WHERE \`name\` = "${PItem}")`;
  con.query(sql , function(err, result){
    // 后续逻辑和之前一致
    if(err) return console.log(err);
    let result2 = 0;
    for (var key6 in result){
      for(var key7 in result[key6])
        result2 = result[key6][key7];
    }
    if(result2 == 0){
      let sql = `INSERT INTO \`items\` (\`name\`, \`buy\`, \`sell\`, \`stock\`, \`maxStock\`) VALUES ("${PItem}", ${Prices[PItem].buy}, ${Prices[PItem].sell}, ${Prices[PItem].stock}, ${Prices[PItem].maxstock})`;
      con.query(sql, function(err, result){
        if(err) return console.log(err);
      });
    }
  });
});

重要提醒:避免SQL注入!

你现在直接把变量拼接到SQL字符串里,存在严重的SQL注入风险!一定要用参数化查询,示例如下:

// 查询的参数化写法
let sql = 'SELECT EXISTS(SELECT * FROM `items` WHERE `name` = ?)';
con.query(sql, [PItem], function(err, result){
  // 处理结果
});

// 插入的参数化写法
let insertSql = 'INSERT INTO `items` (`name`, `buy`, `sell`, `stock`, `maxStock`) VALUES (?, ?, ?, ?, ?)';
con.query(insertSql, [PItem, Prices[PItem].buy, Prices[PItem].sell, Prices[PItem].stock, Prices[PItem].maxstock], function(err, result){
  if(err) return console.log(err);
});

内容的提问来源于stack exchange,提问作者Nikita Ivanov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:41:07