Автор оригинала: Marcos Casagrande.
Я предполагаю, что вы знаете, что при работе с большим количеством данных, Потоки Необходимо использовать, чтобы избежать истощения всей доступной памяти.
Работа с ручьями может показаться сложной, и многие люди пытаются избежать их. Но они чрезвычайно мощны, и если вы хотите освоить Node.js, вы не можете их игнорировать, поскольку большинство встроенных модулей реализуют потоки.
Следующий фрагмент – это то, что я встречал довольно часто при рассмотрении кода, и многие думают, что они используют потоки, они используют их правильно.
(Конечно, я настраивал некоторые вещи, чтобы доказать точку).
const fs = require('fs');
const file = fs.createWriteStream('/tmp/test.txt');
for(let i = 0; i < 1e7; i++) {
file.write("a");
}
Приведенный выше код бросит ошибку, потому что она достигает максимальной памяти, разрешенной для процесса Node.js.
Вы можете увеличить эти ограничения, используя: - max_old_space_size = {mb} Флаг, но это не исправит код, только расширит страдания.
Чтобы понять, почему при использовании потоков он все еще достигает предела памяти, мы должны понимать, как .write Работает и после этого мы узнаем, почему фрагмент плохо закодирован.
.write Возвращает ложь Когда внутренний буфер заполнен, и пришло время промыть его, когда это происходит, мы должны перестать звонить .write снова до Слейте событие испускается. Размер буфера контролируется Highatermark вариант, какой по умолчанию для 16384 (16 КБ)
В примере мы игнорируем возвращенное значение, и мы продолжаем писать, мы не допускаем промыты внутреннего буфера, и именно поэтому он достигает предела памяти.
Итак, вот фрагмент фиксирован:
const fs = require('fs');
const file = fs.createWriteStream('/tmp/test.txt');
(async () => {
for (let i = 0; i < 1e7; i++) {
// Will pause every 16384 iterations until `drain` is emitted
if (!file.write('a')) {
await new Promise(resolve => file.once('drain', resolve));
}
}
})();
К счастью для нас, большую часть времени мы используем потоки, мы используем .pipe который автоматически обрабатывает на нас бэкпред, и это одна из причин, почему вы, возможно, никогда не столкнулись с ошибкой.
const fs = require('fs');
const read = fs.createReadStream('./large-file.txt');
const write = fs.createWriteStream('./larg-file-copy.txt');
read.pipe(write);
В заключение всегда обрабатывать Слейте Мероприятие при работе с жареными потоками или использовать .pipe который обрабатывает это для вас автоматически.