Как детерминистически обработать ситуацию в NodeJS, где асинхронные функции используют память быстрее, чем сборщик мусора восстанавливает ее?
Я столкнулся с проблемой, когда у меня не хватает памяти, потому что сборка мусора не освобождает ресурсы достаточно эффективно, чтобы помешать многим асинхронным функциям использовать их все.
Я не храню ссылки на какие-либо объекты, созданные во время асинхронных функций, поэтому их все можно будет собирать после выхода из области видимости.
Я выполняю асинхронно через дерево каталогов, создавая простой текстовый файл для сопровождения каждого HTML-файла с использованием cheerio.
Я понимаю, что могу, но какая-то задержка или пакетная обработка, чтобы скрипт пытался конвертировать огромное количество файлов одновременно.
Но как я могу сделать это детерминистически? Иногда это работает, иногда я получаю исключение от cheerio, но каждый раз, работая над другим файлом, поэтому я думаю, что это исчерпание памяти и недетерминированное.
Я полагаю, что в JavaScript или NodeJS нет никакого способа контролировать сборку мусора. Что можно сделать?
Мой код:
var fs = require('fs')
, path = require('path')
, cheerio = require('cheerio')
;
var processFile = function(filePath) {
var ext = path.extname(filePath)
, res = false
;
if (ext === '.html' || ext === '.htm') {
res = true;
fs.readFile(filePath, 'utf8', function(err, data) {
var $;
try {
$ = cheerio.load(data);
$('script').remove();
// HTML to text
var pt = $('body').text().replace(/(\s|\r?\n)+/gm, function (ws) {
return /\r?\n.*\r?\n/.test(ws) ? '\n\n' : ' ';
}).trim();
var txtFilePath = filePath.substr(0, filePath.lastIndexOf('.')) + '.txt';
fs.writeFile(txtFilePath, pt, function(err) {
console.log('wrote "' + txtFilePath + '"');
});
} catch (exy) {
console.log('## BANG!', filePath);
throw exy;
}
});
}
return res;
}
var walkP = function(dir, done) {
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walkP(file, function(err, res) {
if (!--pending) done(null);
});
} else {
processFile(file);
if (!--pending) done(null);
}
});
});
});
};
walkP(process.cwd(), function(err, res) {
console.log('Walked ' + res);
});