Автор оригинала: 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
который обрабатывает это для вас автоматически.