Как избежать утечки памяти при рекурсивном создании обещаний?

0

У меня есть ионное приложение, которое должно загружать данные (с разбивкой на страницы) и вставлять их в базу данных рекурсивно (например, конвейер). Я создаю обещания с услугой ($). Проблема в том, что когда я вызываю эту рекурсивную функцию, данные загружаются и вставляются успешно, однако использование памяти всегда увеличивается, и когда цепочка обещаний полностью разрешается, выделенная память все еще используется.

Вот моя рекурсивная функция:

// 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;
}

Примечание. Объект ответа, поступающий из функции loadData, представляет собой большую информацию, иногда содержит 100 000 строк с 18 столбцами. Общее использование памяти составляет 1 ГБ. Я запускаю свои тесты на iPad Air 2.

Я играю с большими данными в своей функции рекурсии, так что мой вопрос немного отличается от других вопросов, связанных с рекурсивной памятью.

Благодарю.

  • 0
    Пожалуйста, сделайте поиск, прежде чем задать вопрос. Дубликат имеет почти точно такую же формулировку, что и ваша, для заголовка, и когда я ищу ваш заголовок, он имеет дубликат в качестве второго попадания (после этого вопроса, конечно).
Показать ещё 5 комментариев
Теги:
ionic-framework
recursion
promise

1 ответ

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
    Это предлагает гораздо более чистый способ написания кода обещания, но я не уверен, что он на самом деле решает реальную точку вопроса - сколько памяти потребляет операция (см. Последний абзац вопроса), о которой думает ОП это утечка (но это еще не показано, является ли это просто проблемой использования памяти или фактической утечкой).
  • 0
    Использование @ jfriend00 памяти должно быть намного ниже, если не использовать вложенное замыкание на 4 уровня, что на самом деле будет очень дорого при выполнении рекурсии. Здесь - никакие замыкания не сохраняются - единственное отслеживание, которое вам нужно, - это следующее обещание, которое начинается только тогда, когда это обещание разрешается, поэтому не нужно хранить память.
Показать ещё 3 комментария
Сообщество Overcoder
Наверх
Меню