提问人:z123 提问时间:10/23/2023 更新时间:10/23/2023 访问量:47
简化循环函数并向 Promise.all() 请求添加定时速率限制
Simplify Looped Function And Adding Timed Rate Limit To Promise.all() Request
问:
我有以下函数,可以循环到图像并将关联的图像添加到项目中。虽然它运行良好,但我正在尝试配置两件事,但无法正常工作。
第一个问题是我有承诺。All(promises),我想按持续时间为其添加速率限制。因此,无论是否有 10、20、50、100 个承诺,我都希望将限制设置为每分钟 60 个请求,但希望所有承诺都能解决。这是否可能,或者我是否必须修改我的代码以使用另一个库或可能的时间间隔。
第二个问题是,如果有一种方法可以简化这个功能,那也会有很大帮助,因为它似乎有太多的循环,可能会减慢 api 的速度。对代码的任何改进将不胜感激
function findImagesForObjectsOrGenerate(listOfObjects, images, isCategory, merchantId) {
let promises = [];
if (listOfObjects.length > 0) {
listOfObjects.forEach((object) => {
const matchedImage = images.find(image => {
return object.id === image.cloverDataId;
});
if (matchedImage) {
object.imageData = matchedImage.imageData;
} else {
promises.push(imageService.generateImageByNameAndSave(object.name, isCategory, object.id, merchantId));
}
})
}
return Promise.all(promises).then(values => {
values.forEach((response, i) => {
if (response) {
listOfObjects[i].imageData = response.imageData;
}
})
return listOfObjects;
});
}
答:
1赞
Ale_Bianco
10/23/2023
#1
您可以实现一个简单的速率限制器,用于控制请求的速率。下面是一个示例,说明如何修改函数以将请求限制为每分钟 60 个:setTimeout
function findImagesForObjectsOrGenerate(listOfObjects, images, isCategory, merchantId) {
const requestsPerMinute = 60;
const delay = 60 * 1000 / requestsPerMinute; // Delay between each request (in milliseconds)
const processObject = async (object) => {
const matchedImage = images.find(image => object.id === image.cloverDataId);
if (matchedImage) {
object.imageData = matchedImage.imageData;
} else {
const response = await imageService.generateImageByNameAndSave(object.name, isCategory, object.id, merchantId);
if (response) {
object.imageData = response.imageData;
}
}
};
const promises = listOfObjects.map(async (object) => {
await processObject(object);
return object;
});
return Promise.all(promises);
}
您可以考虑以下优化方法:
- 如果请求非常大,您可能需要考虑对请求进行批处理,以避免服务器不堪重负。
listOfObjects
- 确保正确处理错误,尤其是与网络相关的错误。
imageService.generateImageByNameAndSave
批处理示例:
function findImagesForObjectsOrGenerate(listOfObjects, images, isCategory, merchantId) {
const MAX_REQUESTS_PER_MINUTE = 60;
const requestsPerBatch = Math.min(MAX_REQUESTS_PER_MINUTE, listOfObjects.length);
let promises = [];
if (listOfObjects.length > 0) {
listOfObjects.forEach((object) => {
const matchedImage = images.find(image => {
return object.id === image.cloverDataId;
});
if (matchedImage) {
object.imageData = matchedImage.imageData;
} else {
promises.push(() => imageService.generateImageByNameAndSave(object.name, isCategory, object.id, merchantId));
}
})
}
// Define a function to execute a batch of promises
function executeBatch(batch) {
return Promise.all(batch.map(fn => fn()));
}
// Split promises into batches
const batches = [];
while (promises.length > 0) {
batches.push(promises.splice(0, requestsPerBatch));
}
// Execute each batch with a delay between them
let index = 0;
function executeNextBatch() {
if (index < batches.length) {
return executeBatch(batches[index++])
.then(() => new Promise(resolve => setTimeout(resolve, 60000 / MAX_REQUESTS_PER_MINUTE)))
.then(executeNextBatch);
}
}
return executeNextBatch().then(() => {
return listOfObjects;
});
}
评论
0赞
z123
10/23/2023
感谢您的回复。我会测试一下,让你知道它是怎么回事。您能否详细说明一下批处理请求,以及它们在防止系统不堪重负方面的作用。您能否提供一个示例,说明如何修改代码以支持批处理,以便更好地理解。再次感谢您的帮助!
0赞
Ale_Bianco
10/23/2023
我添加了一个带有批处理的示例
0赞
z123
10/23/2023
嘿,虽然您的批处理请求代码有效,但我仍然收到错误:429 反复超出速率限制。请在一小时后重试。使用 Open API 时,即使我的请求限制是每分钟 50 个。
0赞
z123
10/24/2023
感谢您的帮助。通过对您的代码进行一些调整,我设法使其正常工作,但我遇到了另一个问题,即 executeNextBatch() 并不总是返回 promise。你能看一下这个链接,看看你是否可以帮助解决这个问题。再次感谢!stackoverflow.com/questions/77347692/......
评论