2016-08-18 98 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是否会这样做,因为我在一年内没有看过它 - 但我希望如此。 –