动态变更数组中按索引安全删除元素的解决方案咨询
问题核心
你担心的索引变更误删风险,本质来自两个可优化的点:
- 虽然
indexOf和splice是同步连续执行(JS单线程特性下这两个操作中间不会插入其他修改数组的逻辑,单流程下这一步本身不会出现计算完索引到执行删除中间数组变更的问题),但批量逐个删除的模式本身容易因数组长度动态变化留下隐患,且每次indexOf遍历查找的效率较低。 - 你用了
setInterval调度异步任务,如果单次处理耗时超过250ms,会出现多个异步处理流程并行操作同一个数组的情况,这种场景下才可能出现删除逻辑互相干扰导致的误删。
最优解决方案
直接放弃按索引删除的模式,改用按值批量过滤的方式更新数组,完全规避索引相关的所有问题,同时优化定时调度逻辑避免并发:
- 每次处理时先收集所有需要删除的交易hash到Set中
- 直接对
pendingTxs做过滤,保留不在删除集合中的hash,不需要操作任何索引 - 把
setInterval换成递归setTimeout,确保上一次处理完成后再调度下一次,避免并行处理冲突
修改后代码如下:
async function analyze() { let pendingTxs = [] web3.eth.subscribe('pendingTransactions', function(error, result){ if (error) console.log(error); }) .on("data", function(hash){ pendingTxs.push(hash) }) // 定义递归处理函数,避免setInterval并发问题 async function processPendingTxs() { // 快照当前要处理的所有交易,避免处理过程中新增的交易被纳入本次处理 const currentTxs = [...pendingTxs] if (currentTxs.length === 0) { setTimeout(processPendingTxs, 250) return } const promises = currentTxs.map(pTx => web3.eth.getTransaction(pTx)) const updatedTransactions = await Promise.all(promises) // 收集所有需要删除的交易hash const toDelete = new Set() for (const txUpdated of updatedTransactions) { if (txUpdated?.transactionIndex != null) { toDelete.add(txUpdated.hash) } } // 直接过滤数组,完全不需要操作索引,不会出现误删 if (toDelete.size > 0) { pendingTxs = pendingTxs.filter(hash => !toDelete.has(hash)) } // 处理完成后再调度下一次 setTimeout(processPendingTxs, 250) } // 启动第一次处理 processPendingTxs() } analyze()
方案优势
- 完全规避索引变更导致的误删风险:不需要计算任何索引,直接按hash值过滤,不管数组中间怎么新增元素,都只会删掉确认上链的交易hash
- 效率更高:用Set存待删除hash,过滤的时间复杂度是O(n),比原来每次
indexOf的O(n²)效率高很多 - 避免并行处理冲突:用递归setTimeout替代setInterval,不会出现多个处理流程同时操作数组的情况
内容的提问来源于stack exchange,提问作者flo
相关产品推荐
相关产品推荐

