编写通用封装函数限制Promise.allSettled()调用频率的问题
解决AWS SDK v3批量执行命令的TypeScript类型错误
问题背景
使用AWS JavaScript SDK v3时,批量并行提交API命令(超过10个)会失败,需要编写通用分批执行函数,但调用client.send()时出现TypeScript错误:
This expression is not callable. Each member of the union type '{ <InputType extends ServiceInputTypes, OutputType extends ServiceOutputTypes>(command: Command<...>): Promise<...>; ... }' has signatures, but none of those signatures are compatible with each other.ts(2349)
错误根源
当客户端是多个AWS服务客户端的联合类型,或者命令数组包含不同服务的命令时,TypeScript无法推断出send方法的兼容签名——不同服务客户端的send方法泛型约束(如各自的ServiceInputTypes/ServiceOutputTypes)存在差异,导致联合后的方法签名无法统一匹配。
解决方案
方案1:限定单一客户端与匹配命令(推荐)
针对同一服务的批量命令,通过泛型约束明确客户端与命令的类型匹配,避免联合类型冲突:
import { Command, SmithyResolvedConfiguration } from "@aws-sdk/smithy-client"; /** * 分批执行同一客户端的API命令 * @param client AWS服务客户端实例 * @param commands 与客户端匹配的命令数组 * @param batchSize 每批并行执行的命令数量,默认10 * @returns 所有命令的执行结果(已settled) */ async function batchExecute< Client extends { send: <InputType, OutputType>( command: Command<any, InputType, any, OutputType, SmithyResolvedConfiguration<any>> ) => Promise<OutputType>; }, Cmd extends Command<any, any, any, any, SmithyResolvedConfiguration<any>> >( client: Client, commands: Cmd[], batchSize: number = 10 ): Promise<PromiseSettledResult<Awaited<ReturnType<Client['send']>>>[] { const results: PromiseSettledResult<any>[] = []; for (let i = 0; i < commands.length; i += batchSize) { const batch = commands.slice(i, i + batchSize); const batchResults = await Promise.allSettled( batch.map(command => client.send(command)) ); results.push(...batchResults); } return results; } // 使用示例(S3客户端) import { S3Client, ListObjectsV2Command, PutObjectCommand } from "@aws-sdk/client-s3"; const s3Client = new S3Client({ region: 'us-east-1' }); const s3Commands = [ new ListObjectsV2Command({ Bucket: 'my-bucket' }), new PutObjectCommand({ Bucket: 'my-bucket', Key: 'test.txt', Body: 'hello world' }), // 更多S3命令... ]; const allS3Results = await batchExecute(s3Client, s3Commands);
方案2:支持多客户端混合命令(牺牲部分类型安全)
如果需要跨服务批量执行命令,可通过类型断言绕过TypeScript的严格检查:
import { Command } from "@aws-sdk/smithy-client"; /** * 分批执行多客户端混合API命令 * @param tasks 包含客户端与对应命令的任务数组 * @param batchSize 每批并行执行的任务数量,默认10 * @returns 所有任务的执行结果(已settled) */ async function batchExecuteMixed( tasks: Array<{ client: any; command: Command<any, any, any, any, any> }>, batchSize: number = 10 ): Promise<PromiseSettledResult<any>[]> { const results: PromiseSettledResult<any>[] = []; for (let i = 0; i < tasks.length; i += batchSize) { const batch = tasks.slice(i, i + batchSize); const batchResults = await Promise.allSettled( batch.map(({ client, command }) => client.send(command as any)) ); results.push(...batchResults); } return results; } // 使用示例(混合S3与DynamoDB命令) import { DynamoDBClient, ScanCommand } from "@aws-sdk/client-dynamodb"; const mixedTasks = [ { client: s3Client, command: new ListObjectsV2Command({ Bucket: 'my-bucket' }) }, { client: new DynamoDBClient({ region: 'us-east-1' }), command: new ScanCommand({ TableName: 'my-table' }) }, ]; const mixedResults = await batchExecuteMixed(mixedTasks);
关键说明
- 方案1通过泛型约束保证了类型安全性,是批量处理同一服务命令的最优选择;
- 方案2适合跨服务批量操作场景,但会丢失部分类型检查能力,需自行确保客户端与命令的匹配性。
内容的提问来源于stack exchange,提问作者scramjet
相关产品推荐
相关产品推荐

