Рубрики
Без рубрики

Понимание Node.js Пиренные потоки

Читайте дальше, чтобы дальнейшее развитие вашего понимания Node.js запотенных потоков.

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