如何让循环内调用的onScan2函数与onScan同步执行?
解决DynamoDB Scan回调异步执行导致的顺序问题
我来帮你搞定这个异步执行的问题~你遇到的核心问题是documentClient.scan是异步操作——它不会等回调函数onScan2执行完,就直接继续跑后面的代码了。所以你的for循环会先把所有scan请求都发出去,而onScan2要等DynamoDB返回结果才会触发,自然就会延迟到最后执行。
下面给你两种靠谱的解决方案,用Promise和async/await来实现真正的“同步”逻辑:
方案1:逐个等待扫描完成(串行执行)
如果你的扫描操作需要按顺序执行(比如前一个的结果影响后一个),可以用这种方式:
首先把documentClient.scan包装成返回Promise的函数,这样就能用await来等待它完成:
// 把DynamoDB的scan包装成Promise函数,方便用await function scanAsync(params) { return new Promise((resolve, reject) => { documentClient.scan(params, (err, data) => { if (err) { reject(err); // 出错时拒绝Promise } else { resolve(data); // 成功时返回结果 } }); }); } // 把onScan改成async函数,这样就能用await了 async function onScan(err, data) { if (err) { console.log("Unable to scan"); return; } let ps = data.Items || []; if (ps.length === 0) { console.log("unable to add in ps"); return; } // 遍历每一项,先完成当前扫描再继续下一个 for (let i = 0, len = ps.length; i < len; i++) { let routForm = ps[i].a + "-" + ps[i].b; const scanParams = { TableName: q, FilterExpression: "#xe=:xe", ExpressionAttributeNames: { '#xe': 'xe' }, ExpressionAttributeValues: { ':xe': routForm } }; try { // 这里会等待扫描完成,拿到结果后再继续 const data2 = await scanAsync(scanParams); // 把结果赋值给ps[i]的dq属性(原代码里的ps[i]dq应该是笔误哦) ps[i].dq = data2; } catch (scanErr) { console.log(`扫描第${i+1}项时出错:`, scanErr); // 可以根据需求处理错误,比如跳过当前项或者抛出错误 } } // 到这里,所有扫描都已经完成啦!可以继续写后续逻辑 console.log("所有扫描执行完毕,处理后的ps数组:", ps); }
方案2:批量并行扫描(效率更高)
如果你的扫描请求之间没有依赖关系,推荐用这种方式,所有扫描会同时发起,等全部完成后再继续后续逻辑,效率更高:
function scanAsync(params) { return new Promise((resolve, reject) => { documentClient.scan(params, (err, data) => { if (err) reject(err); else resolve(data); }); }); } async function onScan(err, data) { if (err) { console.log("Unable to scan"); return; } let ps = data.Items || []; if (ps.length === 0) { console.log("unable to add in ps"); return; } // 先创建所有扫描请求的Promise数组 const scanTasks = ps.map(async (item, index) => { const routForm = item.a + "-" + item.b; const scanParams = { TableName: q, FilterExpression: "#xe=:xe", ExpressionAttributeNames: { '#xe': 'xe' }, ExpressionAttributeValues: { ':xe': routForm } }; try { const data2 = await scanAsync(scanParams); // 返回处理好的item return { ...item, dq: data2 }; } catch (scanErr) { console.log(`扫描第${index+1}项出错:`, scanErr); // 出错时可以返回原item并标记错误,避免整个批量任务失败 return { ...item, scanError: scanErr }; } }); // 等待所有扫描任务完成,拿到处理后的ps数组 ps = await Promise.all(scanTasks); // 所有扫描完成,继续后续逻辑 console.log("批量扫描完成,处理后的ps数组:", ps); }
为啥原代码会延迟?
再给你捋清楚原代码的执行流程:
- 你在for循环里调用
documentClient.scan(c, onScan2),这个函数会立即发起请求,但不会等结果返回。 - 循环会快速跑完所有迭代,把所有scan请求都发出去。
- 等DynamoDB陆续返回结果后,
onScan2才会被逐个调用——这时候你的for循环早就执行完了,所以你会觉得onScan2总是最后执行。
用Promise和async/await就能让我们用“同步”的写法来处理异步操作,确保后续逻辑只有在所有扫描完成后才会执行~
内容的提问来源于stack exchange,提问作者Ashish Kumbhar
相关产品推荐
相关产品推荐

