2017-10-09 57 views
5

我已經得到了我使用的是API,它允許每秒20所請求的速率限制。所有請求都是基於承諾的,一旦有迴應,承諾將通過API數據解決。Promise.all佔用我所有的RAM

的問題:它含有58K

我設置一個promiseArray承諾所有等待響應。如此緩慢的內存在不斷增加,直到內存不足。在我的具體情況下,我不需要將解析的數據傳遞給我的then(),並且數據耗盡了我所有的RAM。

代碼:

}).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被而不需要解決數據解決?

+2

58,000承諾?!聽起來像你需要有一個切點。如果您獲得的X請求超過X個,請放棄其中一些。如果你得到了很多連接,你應該考慮某種負載平衡,並在多個節點進程中運行你的服務器。 –

+2

我懷疑這對於原生Promise來說是不可能的,因爲他們無法知道所有附加的回調都不會使用這些數據(直到承諾本身是GC'd)。 –

+3

爲了避免存儲響應數據,你可以做一個'promiseArray.push(p.then(()=>'success'))'這會丟棄每個承諾攜帶的數據,並且仍然返回可用的承諾。應該。我有點模糊,因此評論而不是答案。 – SethWhite

回答

3

您將使用較少的內存量,如果你不曾經有58K的承諾,其相關的異步操作和其結果數據一次激活。

而是要同時運行X操作,然後當一個人完成,在你開始下一個在同一時間比X絕不會在飛行中,比X承諾在使用一次絕不會。

您可以嘗試使用適當的X值。值1是順序操作,但通常可以通過使用更高的X值來提高總體端到端操作時間。如果所有請求都擊中同一主機,那麼X可能不會超過5-10(因爲給定的主持人不能一次做很多事情,並要求它做得比一次做得更多,而只是減慢速度)。

如果每一個請求到不同的主機,那麼你可能能夠使X高。實驗會爲您提供峯值內存使用率和總體吞吐量的最佳值,並且取決於您的具體情況。

Bluebird的Promise.map()有一個併發選項,可以爲你做到這一點,但也有許多方法可以在同一時間只對X進行編碼。

這裏有管理的一些其他編碼的例子有多少在飛行時間:

Make several requests to an API that can only handle 20 request a minute

How to execute promises in series?

unable to complete promises due to out of memory

Fire off 1,000,000 requests 100 at a time

How to make it so that I can execute say 10 promises at a time in javascript to prevent rate limits on api calls?


如果您不需要解析數據,可以允許它是GCed越早通過更換這樣的:

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(); 
    }); 
} 
+0

添加了一個實現,用於控制同時有多少個請求正在「正在運行」。 – jfriend00