如何在不修改主代码时合并TypeScript Promise实现单次API请求?
问题描述
现有如下TypeScript代码:
async function my_function(arg: string): Promise<string> { fetch("http://localhost:8000/api.php?args=" + arg); ... } const items = ["100","98","35","400"]; let result = await Promise.all(items.map(my_function));
我的API支持多参数请求:
http://localhost:8000/api.php?args=100,98,35,400
注意我只能修改my_function的函数体代码,不能更改该函数签名。请问能不能在my_function内部把其他Promise合并,实现只发起一次fetch请求且不修改主代码的目标?
解决方案
完全可以实现,核心思路就是用函数静态变量或闭包来收集同一批次调用的参数,延迟发起请求,等所有参数收集完毕后只发一次请求,再把结果分发给各个调用对应的Promise。
具体实现代码如下:
async function my_function(arg: string): Promise<string> { // 用static变量跟踪当前批次的请求状态,同批次所有调用共享这些变量 static batch: { args: string[], resolver: (results: string[]) => void } | null = null; static batchPromise: Promise<string[]> | null = null; return new Promise((resolve) => { // 如果当前没有正在处理的批次,初始化新批次 if (!batch) { batch = { args: [], resolver: null! }; // 创建一个Promise,等待参数收集完再发起请求 batchPromise = new Promise<string[]>((res) => { batch!.resolver = res; // 用setTimeout延迟执行,确保Promise.all里的所有my_function调用都能把参数加进来 setTimeout(async () => { try { // 发起批量请求 const response = await fetch(`http://localhost:8000/api.php?args=${batch!.args.join(',')}`); // 假设API返回的结果数组顺序和参数顺序一致,根据实际情况调整解析逻辑 const results = await response.json(); batch!.resolver(results); } catch (err) { // 错误处理:给所有Promise返回默认值,或者抛出错误,按需调整 batch!.resolver(batch!.args.map(() => '')); } finally { // 重置批次状态,准备处理下一批请求 batch = null; batchPromise = null; } }, 0); }); } // 把当前参数加入批次 batch.args.push(arg); // 等待批量请求完成,根据参数索引返回对应结果 batchPromise.then((results) => { const index = batch!.args.indexOf(arg); resolve(results[index]); }); }); }
要点说明
- 这里用了TypeScript函数的
static属性来存储批次状态,也可以用模块级的变量替代,效果一样。 setTimeout的作用是给Promise.all中的所有my_function调用留足时间收集参数,确保不会提前发起请求。- 假设API返回的结果数组顺序和传入的参数顺序完全匹配,如果API返回的是键值对(比如
{ "100": "结果1", "98": "结果2" }),需要把结果匹配逻辑改成resolve(results[arg])即可。 - 错误处理部分可以根据业务需求调整,比如统一抛出错误,或者给每个调用返回特定的错误值。
内容的提问来源于stack exchange,提问作者Bob5421
相关产品推荐
相关产品推荐

