我为我使用的API提供了一个速率限制器,它每秒允许20个请求。所有请求均基于承诺,并且一旦有响应,承诺将使用API数据进行解析。
问题:
我设置了一个promiseArray,其中包含58k个都在等待响应的Promise。如此缓慢地增加内存,直到内存用完。在我的特定情况下,我不需要将解析的数据传递给我then(),并且数据耗尽了我的所有RAM。
then()
代码:
}).then(() => { // 2. Crawl for all clanprofiles from these leaderboards const promiseArray = [] for (let i = 0; i < clanTags.length; i++) { // Resolved data from getClanProfile() is eating up all my RAM const p = backgroundScheduler.getClanProfile(clanTags[i], true) promiseArray.push(p) } return Promise.all(promiseArray) }).then(() => {
那么,有没有一种方法可以等待到promiseArray被解析而不需要解析的数据呢?
如果您没有58k的诺言,它们关联的异步操作和它们的结果数据一次都处于活动状态,则将使用较少的内存。
相反,您希望一次运行X次操作,然后在一次操作完成时,启动下一个操作,一次不超过X个,一次使用不超过X个承诺。
您可以尝试使用适当的X值。值为1表示顺序操作,但通常可以通过使用更高的X值来改善总体端到端操作时间。如果所有请求都到达同一主机,则X为可能不会超过5到10个(因为给定的主机不能一次真正完成很多事情,而要求它立即完成很多事情,只会减慢速度)。
如果每个请求都针对不同的主机,则可以提高X。实验将为您提供峰值内存使用量和总体吞吐量的最佳值,并且在某种程度上取决于您的具体情况。
蓝鸟的Promise.map()有一个并发选项可以为您完成此任务,但是也有很多方法可以同时为飞行中的X进行编码。
Promise.map()
以下是一些其他编码示例,它们可以一次管理多少个航班:
向一次只能处理20个请求的API发出多个请求
如何连续执行承诺?
由于内存不足而无法完成承诺
一次触发1,000,000个请求100
如何做到这一点,以便我可以在JavaScript中一次执行10个诺言,以防止api调用的速率限制?
如果不需要已解析的数据,则可以通过如下替换它来尽快对其进行GC:
const p = backgroundScheduler.getClanProfile(clanTags[i], true).then(data => { return 0; // make resolved value just be a simple number // so other data is now eligible for GC }); promiseArray.push(p)
而且,这是一个简单的实现,它可以同时迭代一个不超过X个正在运行的请求的数组:
// takes an array of items and a function that returns a promise // runs no more than maxConcurrent requests at once function mapConcurrent(items, maxConcurrent, fn) { let index = 0; let inFlightCntr = 0; let doneCntr = 0; let results = new Array(items.length); let stop = false; return new Promise(function(resolve, reject) { function runNext() { let i = index; ++inFlightCntr; fn(items[index], index++).then(function(val) { ++doneCntr; --inFlightCntr; results[i] = val; run(); }, function(err) { // set flag so we don't launch any more requests stop = true; reject(err); }); } function run() { // launch as many as we're allowed to while (!stop && inFlightCntr < maxConcurrent && index < items.length) { runNext(); } // if all are done, then resolve parent promise with results if (doneCntr === items.length) { resolve(results); } } run(); }); }