JavaScript中Promise.all实现DynamoDB批量插入的相关疑问
示例代码
'use strict'; const AWS = require('aws-sdk'); const promiseFunction = (item) => { const database = new AWS.DynamoDB(); const params = { TableName: 'some-table', Item: item } try { //database.putItem(params).promise(); //3 //Updated as per the comments.. return database.putItem(params).promise(); //3 } catch (err) { console.log(`Error`); } } const test = async () => { const arr = []; try { for (let data=1;data<=1000;data++) { const obj = { data: {N: data.toString()}} arr.push(promiseFunction(obj)); //1 } const result = await Promise.all(arr); //2 } catch (e) { console.log(`Error`); } } test();
问题解答
1. 第//2行代码处,是否只有当//1行所有基于Promise的函数执行完毕后,result变量才会存储所有Promise的resolve或reject结果?
是,但要注意两种边界情况:
- 只有数组中所有Promise都变为成功(fulfilled)状态时,
result才会接收到所有结果组成的数组,顺序和你push进数组的Promise顺序完全一致。 - 如果任意一个Promise变为失败(rejected)状态,
Promise.all会立刻抛出错误,代码直接进入catch块,result不会被赋值,也不会等待其余未完成的Promise执行结束。
2. 我仅将promiseFunction的调用结果推入数组,并未主动调用DynamoDB的putItem接口,为什么promiseFunction会执行并向DynamoDB插入数据?按照技术原理,是否所有putItem操作应该在//2行才开始并行执行?
这是JavaScript中Promise的核心执行逻辑:Promise实例在创建的时候就已经开始执行内部异步逻辑,不是等到await/then调用时才启动。
你在//1位置写的是arr.push(promiseFunction(obj)),这里已经调用了promiseFunction函数,函数内部的database.putItem(params).promise()会立刻执行,DynamoDB的写入请求此时就已经发出去了,push到数组里的只是已经处于pending状态的Promise实例。//2位置的await Promise.all(arr)只是等待所有已经启动的请求执行结束,不是在这个位置才启动请求。
3. 上述代码在Promise.all的使用以及并行执行插入操作的逻辑上是否合法合理?请给出相关建议。
代码语法合法,但生产环境使用存在较多问题,优化建议如下:
- 全局复用DynamoDB客户端:不要在
promiseFunction中每次调用都实例化新的DynamoDB客户端,AWS SDK的客户端是线程安全的,全局初始化一次即可,反复实例化会额外消耗性能,重复执行配置加载、签名初始化等逻辑。 - 控制并发请求数避免流控:DynamoDB有写入容量(WCU)限制,直接发起1000个并行写入请求大概率会触发限流错误,甚至直接达到SDK重试上限导致写入失败。建议换成
BatchWriteItem批量写入接口,单次最多支持写入25条数据,把1000条数据拆分为多个批次,控制并行批次数量在合理范围(比如同时跑5~10个批次),避免超过流控阈值。 - 完善错误处理逻辑:当前的catch块仅打印通用的
Error字段,没有输出错误详情、失败的请求参数,出问题无法排查。建议在catch块中完整打印错误对象,同时如果需要容忍部分写入失败的场景,可以将Promise.all换成Promise.allSettled,执行完成后单独筛选失败的请求做重试。 - 若代码运行在Serverless环境(比如Lambda),需要注意执行超时时间,1000条写入如果触发重试很容易超出超时限制,建议配合消息队列做异步削峰处理。
内容的提问来源于stack exchange,提问作者user8479984
相关产品推荐
相关产品推荐

