Что такое потоки?
Поток — это абстрактный интерфейс, который позволяет непрерывно выполнять определенные задачи. Поток является EventEmitter , который реализует различные методы. Пользователь может использовать потоки для выполнения различных задач, таких как чтение, запись и преобразование функций.
В среде Node.js потоки используются для работы с потоковыми данными. Он предоставляет пользователям API, который помогает им в создании потокового интерфейса. Данные здесь принимаются по частям, а также читаются по частям.
Трубопроводы
Как следует из названия, трубопровод — это процесс, который обеспечивает потоки данных без каких-либо помех. Трубопровод передает выходные данные потока в качестве входных данных для другого потока и помогает поддерживать плавный рабочий процесс. Как долго будет продолжаться трубопровод, зависит от того, что пользователь подает в систему.
Вот как вы можете выполнить механизм трубопровода:
Начните с создания js-файла main.js, имеющего следующий код:
JavaScript
1
var fs = require("fs");
2
// Insert a readable stream
3
var readerStream = fs.createReadStream('input.txt');
4
// Insert a writable stream
5
var writerStream = fs.createWriteStream('output.txt');
6
// Pipe the read and write operations
7
// read input.txt and write data to output.txt
8
readerStream.pipe(writerStream);
9
console.log("Program Ended");
10
// After that run the main.js to see the output −
11
$ node main.js
12
// Verify if it is what you had expected.
Вы можете использовать дополнительную логику для автоматического переключения между режимами. Используя трубопровод, пользователи могут создавать двунаправленные потоки, которые могут выполнять различные функции. Механизм трубопровода останавливается, как только запускаются конечные функции. Пользователи могут обойти функцию завершения, вставив дополнительный необязательный объект конфигурации с функцией завершения в качестве логического значения.
Вы можете также как:
Понимание потоков в Node.js .
Цепные потоки
Процесс, похожий на Piping, Chaining, используется для последовательного выполнения нескольких задач. Это метод, который соединяет вывод потока с другим потоком и тем самым выполняет несколько операций вместе. Вот пример того, как это работает:
Создайте js-файл с именем main.js со следующим кодом:
JavaScript
xxxxxxxxxx
1
var fs = require("fs");
2
var zlib = require('zlib');
3
// Compress the file Detox.txt to Detox.txt.gz
4
fs.createReadStream(Detox.txt')
5
.pipe(zlib.createGzip())
6
.pipe(fs.createWriteStream(Detox.txt.gz'));
7
console.log("File Compressed.");
После добавления кода запустите main.js, чтобы увидеть результат:
Оболочка
xxxxxxxxxx
1
$ node main.js
2
Verify the Outcome.
4
File has successfully been compressed.
Вы обнаружите, что Detox.txt теперь сжат и создал файл Detox.txt.gz в текущем каталоге. Вы можете распаковать тот же файл, используя следующий код:
JavaScript
xxxxxxxxxx
1
var fs = require("fs");
2
var zlib = require('zlib');
3
// Decompress the file input.txt.gz to Detox.txt
4
fs.createReadStream(Detox.txt.gz')
5
.pipe(zlib.createGunzip())
6
.pipe(fs.createWriteStream(Detox.txt'));
7
console.log("File Decompressed.");
Как мы делали раньше, мы можем запустить наш файл, чтобы увидеть результат:
Оболочка
xxxxxxxxxx
1
$ node main.js
2
3
Verify the Outcome.
4
File Decompressed.
Типы потоков
Потоки способны выполнять различные функции в зависимости от категории, к которой они относятся. Мы можем разделить потоки на следующие категории:
Читаемые Потоки
Читаемый поток, как следует из названия, позволяет пользователям читать данные. Они бывают двух вариантов или двух разных режимов чтения: « Приостановлено» и « Плавно» . Все читаемые потоки по умолчанию работают в режиме паузы. Это означает, что пользователи должны запрашивать вывод из потока. Текущий режим обеспечивает непрерывную передачу данных.
fs.createReadStream
Функция используется для создания читаемого потока, или вы не можете read()
непрерывно , пока все заканчивается чтения данных. Для создания потока вам понадобится дополнительный бит кода. Вот пример потока чтения:
JavaScript
xxxxxxxxxx
1
var fs = require('fs');
2
var readableStream = fs.createReadStream('file.txt');
3
var data = '';
4
var chunk;
5
readableStream.on('readable', function() {
6
while ((chunk=readableStream.read()) != null) {
7
data += chunk;
8
}
9
});
10
readableStream.on('end', function() {
11
console.log(data)
12
});
В приведенном выше примере read()
функция будет считывать данные из внутреннего буфера и возвращать их пользователю. Как только нет данных для дальнейшего чтения, цикл завершается и возвращается null
.
Анализируя читаемый поток, мы понимаем, что data
событие и end
событие являются его наиболее важными событиями. Событие данных генерируется всякий раз, когда поток отправляет кучу данных пользователю. Событие end приходит на сцену, когда больше не осталось данных, которые будут использованы потоком.
Записываемые потоки
Другие EventEmitter
, доступные для записи потоки, позволяют пользователям писать в выбранный пункт назначения. Мы используем write()
функцию для запуска потока записи. API здесь проще и предпочитает использовать методы вместо событий. Пользователям очень легко выучить доступный для записи поток. Вот основной пример доступных для записи потоков:
JavaScript
xxxxxxxxxx
1
var fs = require('fs');
2
var readableStream = fs.createReadStream('file1.txt');
3
var writableStream = fs.createWriteStream('file2.txt');
4
5
readableStream.setEncoding('utf8');
6
7
readableStream.on('data', function(chunk) {
8
writableStream.write(chunk);
9
});
Приведенный выше пример является довольно стандартным. Мы используем читаемый поток для чтения входных данных, а затем write()
поток записывает его в указанное место назначения. Вы получите логическое значение, как только функция будет выполнена успешно. Если возврат верен, процесс завершен. В случае любого несоответствия функция вернет false.
Два значимых события, как правило, прикрепляются к доступному для записи потоку - события сток и окончание . Событие утечки является индикатором того, что поток способен принимать больше данных. Принимая во внимание, что событие финиша означает, что базовая система получила все данные.
Дуплексные потоки
Первые два потока хороши для выполнения отдельных функций. С дуплексными потоками вы можете выполнять обе их функции совместно. Это почти как ребенок, наследующий гены как матери, так и отца. В основном дуплексный поток состоит из двух отдельных потоков, один из которых предназначен для потока, а другой - для потока. Ниже приведен пример основного дуплексного потока:
JavaScript
xxxxxxxxxx
1
net.createServer(socket => {
2
socket.pipe(socket)
3
}).listen(8001);
В данном примере сокет был передан самому себе, что, в свою очередь, обеспечит создание дуплексного потока. Первый сокет является читаемым потоком, а следующий - записываемым потоком. Всякий раз, когда вы запускаете функцию, она netcat
будет пытаться отправить некоторые данные на сервер. С другой стороны, сервер попытается записать полученные данные.
Трансформировать потоки
Поток преобразования - это более сложный дуплексный поток, в котором пользователь читает то, что он отправляет, в качестве входных данных. В отличие от дуплексного потока, читатель здесь имеет доступ к введенным им данным. Это также относится к тому факту, что выходной сигнал зависит от входного сигнала, предоставленного машине. Мы используем функцию для создания потока преобразования. transformStream
Вот простой пример потока преобразования:
JavaScript
xxxxxxxxxx
1
const readableStream = fs.createReadStream('file');
2
const transformStream = zlib.createGzip();
3
const writableStream = fs.createWriteStream('file.gz');
4
readableStream.pipe(transformStream).pipe(writableStream);
Приведенный выше поток преобразования заархивирует файл при запуске. zlib
Функция входит в игру , когда нам нужно вывод , что это либо намного больше или намного меньше , чем на входе. В этом случае он был использован для создания меньшего вывода.
Совместимость потоков с асинхронными генераторами и асинхронными итераторами
С помощью асинхронных генераторов мы можем создать читаемый поток Node.js. Нам нужно использовать Readable.from()
функцию, как показано в примере ниже:
JavaScript
xxxxxxxxxx
1
const { Readable } = require('stream');
2
3
async function * generate() {
4
yield 'a';
5
yield 'b';
6
yield 'c';
7
}
8
9
const readable = Readable.from(generate());
10
11
readable.on('data', (chunk) => {
12
console.log(chunk);
13
})
Мы также можем использовать читаемый поток с асинхронными итераторами, используя async()
функцию. Вот пример:
JavaScript
xxxxxxxxxx
1
(async function() {
2
for await (const chunk of readable) {
3
console.log(chunk);
4
}
5
})();
Эти итераторы используются для предотвращения необработанных ошибок после уничтожения путем регистрации постоянного обработчика ошибок.
Мы также можем передавать записываемые потоки от асинхронных итераторов, но мы должны быть осторожны с обратным давлением и ошибками.
Преимущества потоков
Использование во всем мире должно иметь некоторые преимущества, связанные с потоками. Помимо факта, что даже новичок может реализовать их, вот некоторые другие преимущества использования потоков:
Эффективность времени
В чем выгода сети? Это гарантирует, что человек сзади путешествует вместе с человеком впереди. Что касается потоковой среды, то благодаря конвейеру выходные данные потока передаются как входные данные другого потока. Это обеспечивает своевременную обработку массивных данных благодаря постоянному потоку. Трубопровод позволяет обрабатывать несколько этапов одновременно, тем самым сокращая ненужные потери времени.
Пространственная эффективность
Что вы делаете, когда у вас небольшой буфер, но больший входной файл? Вы создаете поток для отображения данных как можно скорее, чтобы гарантировать, что буфер остается свободным для следующего лота. Предположим, вы хотите прочитать файл размером около 35 МБ и вывести на экран вывод. Но буфер ограничен 25 МБ. Что вы делаете в такой ситуации?
Чтобы предотвратить кризис, создайте читаемый поток. Что это будет делать? Как только часть данных будет считана из вашего ввода, вы можете поместить стопку в буфер, отобразить ее и очистить, чтобы освободить место для следующего лота. Это гарантирует, что данные не будут пропущены и будут полностью обработаны.
Заключение
Потоки являются неотъемлемой частью Node.js и помогли упростить код для разработчиков. С помощью потоков разработчики могут создавать код гораздо быстрее, чем раньше. В связи с тем, что доступно много других сред, которые делают то же самое, потоки являются причиной, по которой большинство людей остаются на Node.js. Эта статья должна была дать вам четкое представление о том, что такое потоки и как они работают.