2016-08-18 44 views
-1

我有一個離子應用程序需要下載數據(分頁),並將其插入數據庫遞歸(如管道)。我正在用(Angular's)$ q服務創建承諾。問題是,當我調用這個遞歸函數時,數據正在被下載並插入成功,但是內存使用量一直在增加,並且當promise鏈完全解析時,分配的內存仍然在使用中。如何在遞歸創建promise時避免內存泄漏?

這裏是我的遞歸函數:

// offset: last downloaded row count 
// limit: row count to download at each page 
// numRows: row count to download at all 
function dowloadAndInsert(offset, limit, numRows) { 
    var deferred = $q.defer(); 

    // Recursion step: We do not reached at the end of data 
    if((offset + limit) <= numRows) { 

     // Download the data 
     downloadData(offset, limit) 
      .then(function(response) { 

       // Insert the data 
       insertData(response) 
        .then(function(insertTime) { 

         // Recursion step 
         dowloadAndInsert(offset + limit, limit, numRows) 
          .then(function() { 
           deferred.resolve(); 
          }) 
          .catch(function(reason) { 
           deferred.reject(reason); 
          }); 
        }) 
        .catch(function(reason) { 
         deferred.reject(reason); 
        }); 
      }) 
      .catch(function(reason) { 
       deferred.reject(reason); 
      }); 
    } 

    // Base case: We reached at the end of data 
    else { 
     var remainingRows = numRows % limit;  // Means the last limit actually 

     // If exists, insert remaining rows 
     if(remainingRows !== 0) { 

      // Download the last piece of data 
      downloadData(offset, remainingRows) 
       .then(function(response) { 

        // Insert the last piece of data 
        insertData(response) 
         .then(function(insertTime) { 

          // Base case, successfully downloaded and inserted everything 
          deferred.resolve(); 
         }) 
         .catch(function(reason) { 
          deferred.reject(reason); 
         }); 
       }) 
       .catch(function(reason) { 
        deferred.reject(reason); 
       }); 
     } 

     else { 
      // Base case, successfully downloaded and inserted everything 
      deferred.resolve(); 
     } 
    } 

    return deferred.promise; 
} 

注:響應對象從downloadData功能未來是一個很大的數據時,它有時會包含100.000行18列。內存使用總量變成1GB。我在iPad Air 2上運行我的測試。

我在遞歸函數中使用大數據,因此我的問題與其他遞歸內存泄漏問題有點不同。

感謝。

+1

可能重複[如何用遞歸JavaScript承諾來阻止內存泄漏?](http://stackoverflow.com/questions/15027192/how-do-i-stop-memory-leaks-with-recursive- javascript-promises) –

+0

請在提問前進行搜索。複製品的標題與您的標題幾乎完全相同,當我搜索您的標題時,它具有作爲第二個標題的複製品(當然這個問題之後)。 –

+1

神聖推遲反模式:O –

回答

3

你的代碼工作方式太硬,承諾鏈,所以當你的小遞延舞 - 你可能真的只是鏈,其應解決泄漏爲更好的代碼的副作用承諾:

function dowloadAndInsert(offset, limit, numRows) { 
    const start = offset, 
     numFetch = ((offset + limit) <= numRows ? limit : numRows % limit; 
    if(numFetch === 0) { 
    return Promise.resolve(); // we're done; 
    } 
    return downloadData(start, end). 
      then(insertData). 
      then(downloadAndInsert.bind(null, offset + numFetch, limit, numRows); 
} 

這就是整個代碼,它說:

  • 檢查,我需要多少行獲取並插入。
  • 如果我不需要再取行 - 只是返回一個空的承諾。
  • 否則會抓取儘可能多的數據 - 然後獲取剩餘的行。
+0

這提示了一個更簡潔的方式來編寫承諾代碼,但我不確定它是否真正解決了問題的實際問題,即操作正在消耗多少內存(請參閱問題的最後一段),OP似乎認爲是泄漏(但是這還沒有顯示這是否僅僅是內存使用問題或實際泄漏)。 – jfriend00

+0

@ jfriend00當不使用4級嵌套閉包時,內存使用率應該低得多,這在實現遞歸時確實非常昂貴。在這裏 - 沒有關閉 - 唯一需要的跟蹤是下一個承諾,並且只有當這個承諾解決時纔會開始,所以不必記憶。 –

+0

現在是完全公平的 - 泄漏是棘手的術語 - 如果我們考慮泄漏只有最終不會被清除的東西 - 你是對的 - 但如果我們考慮泄漏事物消耗越來越多的內存作爲一個操作時,他們不必 - 這個代碼不會泄漏到一個智能承諾庫中,它可以在追蹤最終承諾後解決中間承諾。我不確定$ q是否會這樣做,因爲我在一年內沒有看過它 - 但我希望如此。 –