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

使用web3 BatchRequest循环发送请求仅生效最后一个值的问题

解决Web3 BatchRequest循环中所有请求使用最后一个值的问题

这个问题我太熟了——典型的JavaScript闭包陷阱在搞鬼!

问题原因

你在forEach循环里添加的send.request回调函数,并没有捕获到当前迭代的d的值,而是捕获了d变量的引用。当batch.execute()执行的时候,整个forEach循环已经跑完了,此时d变量指向的是数组的最后一个元素(也就是test4那项),所以所有请求都会复用这个最后的值。

修复方案

下面两种方法都能解决这个问题,选你顺手的就行:

方案1:在forEach迭代内创建块级作用域的变量副本

通过let声明一个当前迭代的变量副本,让每个回调函数捕获这个独立的副本引用:

let batch = new this.web3.BatchRequest(); 
const arr = [ 
  {name: "test1", att: 100, def: 100}, 
  {name: "test2", att: 100, def: 100}, 
  {name: "test3", att: 100, def: 100}, 
  {name: "test4", att: 100, def: 100}, 
] 
arr.forEach((d) => {
  // 用let创建当前迭代数据的独立副本,形成块级作用域
  let currentItem = d;
  batch.add(this.contract.methods.createCountry(currentItem.name, currentItem.att, currentItem.def, 10, this.account).send.request(this.contractObject, (err, res) => { 
    if (err) { 
      throw err; 
    } else { 
      console.log(res); 
    } 
  })); 
}); 
console.log(batch); 
batch.execute(); 

方案2:改用for...of循环

for...of的每次迭代都会自动创建新的块级作用域变量,天然避免闭包引用问题:

let batch = new this.web3.BatchRequest(); 
const arr = [ 
  {name: "test1", att: 100, def: 100}, 
  {name: "test2", att: 100, def: 100}, 
  {name: "test3", att: 100, def: 100}, 
  {name: "test4", att: 100, def: 100}, 
] 
// 替换forEach为for...of
for (const d of arr) {
  batch.add(this.contract.methods.createCountry(d.name, d.att, d.def, 10, this.account).send.request(this.contractObject, (err, res) => { 
    if (err) { 
      throw err; 
    } else { 
      console.log(res); 
    } 
  })); 
}
console.log(batch); 
batch.execute(); 

额外说明

既然你已经通过Remix和单独调用确认了合约本身没问题,那核心问题就完全出在JavaScript的变量引用机制上。上面的两种方法都能确保每个BatchRequest里的请求使用的是当前迭代的元素值,不会再全部变成最后一项。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:20:56