Автор оригинала: Janith Kasun.
Вступление
Потоки – это несколько расширенной концепции, чтобы понять. Таким образом, в этой статье мы пойдем вместе с некоторыми примерами для лучшего понимания и познакомить вас с несколькими концепциями по пути.
Что такое поток
Простые термины потоки используются для чтения из ввода или записи для вывода последовательно. Большую часть времени потоки используются для чтения или записи из непрерывного источника или сравнительно большой.
Например, давайте предположим, что вы должны прочитать большой файл. Если размер файла больше вашего свободного пространства памяти, вы не можете прочитать весь файл в память, чтобы обработать его. Вы должны прочитать его штуку по частям и обрабатывать каждый кусок, который может быть разделен линией, например.
Другим примером непрерывного источника является сетевая связь – например, приложение чата, где данные должны постоянно текут от отправителя на приемник.
Потоки в Node.js.
Поток
Модуль – это родной модуль, который поставляется по умолчанию в Node.js. Поток
является примером Eventemitter Класс, который обрабатывает события асинхронно в Node.js. Из-за их суперкласса потоки по своей природе насущены.
В Node.js есть 4 типа потоков:
- Пирена: Используется для записи данных последовательно
- Читабельный: Используется для чтения данных последовательно
- Дуплекс: Используется как для чтения и записи данных последовательно
- Преобразование: Где данные могут быть изменены при написании или чтении. Возьмите сжатие для примера, с таким потоком, вы можете написать сжатые данные и прочитать распарковываемые данные.
Давайте посмотрим на несколько примеров потоков.
Пиренные потоки
Прежде всего, давайте создадим писательский поток и напишите некоторые данные в файл:
const fs = require('fs'); const file = fs.createWriteStream('file.txt'); file.write('hello world'); file.end(', from streams!');
В этом коде мы использовали модуль файловых систем для создания записи писателя в файл ( file.txt
) и напишите 2 отдельных куска к нему: Здравствуйте, мир
и , от потоков
Отказ
В отличие от fs.writefile ()
Где нам нужно одновременно написать содержимое файла, используя поток, который мы можем записать кусок контента кусочком.
Чтобы моделировать непрерывный вход, мы могли бы сделать что-то вдоль линий:
const fs = require('fs'); const file = fs.createWriteStream('file.txt'); for (let i = 0; i < 10000; i++) { file.write('Hello world ' + i); } file.end();
Это напишет Здравствуйте, World + {I}
Десять тысяч раз, а затем закончите поток:
Hello world 0 Hello world 1 Hello world 2 Hello world 3 Hello world 4 ...
Пожалуйста, помните, чтобы .end ()
ваши потоки после того, как вы закончите, используя их, поскольку Готово
Событие отправляется после .end ()
метод был вызван.
Это означает, что тело потока было вставлено в наш файл.
Читаемые потоки
Теперь давайте посмотрим на другой простой пример, читая файл с помощью потока. Мы можем прочитать кусок файлов с помощью куска вместо того, чтобы читать полный контент в памяти, используя читаемый поток:
const fs = require('fs'); const readableStream = fs.createReadStream('./article.md', { highWaterMark: 10 }); readableStream.on('readable', () => { process.stdout.write(`[${readableStream.read()}]`); }); readableStream.on('end', () => { console.log('DONE'); });
Подобно созданию записи пирета, мы создали читаемый поток, вызывая .CreateSeadStream ()
метод.
При буферизации (сегментирование данных в куски) размер буфера зависит от Highatermark
Параметр, который передается в поток конструктора.
Значение по умолчанию этого параметра составляет 16384 байта (16 кБ), поэтому, если вы не переопределите параметр, поток будет прочитать куски 16 КБ и передавать их для обработки.
Поскольку мы используем небольшой текстовый файл, это имеет больше смысла использовать небольшое значение для нашего примера, поэтому текст будет забит 10 символов.
В нашем примере выше мы просто напечатали кусок данных, которые мы получили, за исключением кронштейнов вокруг него, чтобы вы могли легко увидеть различные куски. Выход нашего кода выглядит так:
[### Introd][uction St][reams are ][a somewhat][ advanced ][concept to][ understan][d. So in t][his articl][e, we will][ go along ][with some ][examples f][or a bette][r understa][nding and ][introduce ][you to a f][ew concept][s along th][e way. ##][# What is ][a Stream ][In simple ]...
Дуплексные потоки
С возобновляемыми, так и читаемыми потоками, вы можете прыгнуть в пример, используя дуплексные потоки – которые по существу объединяются оба.
Мы будем продемонстрировать их, используя простой HTTP-сервер, построенный с использованием Node.js ‘outsious http
модуль. Пример, используемый здесь от официального Node.js Документация Отказ
Поскольку серверы получают запросы, а затем отправляют ответы, они хороший пример для дуплексных потоков, которые обрабатывают оба – читаемый поток, будут действовать как непрерывный запрос, и запись записи будет действовать как ответ.
Во-первых, давайте импортируем HTTP-модуль:
const http = require('http');
Теперь давайте создадим простой HTTP-сервер:
const server = http.createServer((req, res) => { // `req` is an http.IncomingMessage, which is a Readable Stream. // `res` is an http.ServerResponse, which is a Writable Stream. let body = ''; // Get the data as utf8 strings. // If an encoding is not set, Buffer objects will be received. req.setEncoding('utf8'); // Readable streams emit 'data' events once a listener is added. req.on('data', (chunk) => { body += chunk; }); // The 'end' event indicates that the entire body has been received. req.on('end', () => { consol.log(body); try { // Send 'Hello World' to the user res.write('Hello World'); res.end(); } catch (er) { res.statusCode = 400; return res.end(`error: ${er.message}`); } }); });
req
Параметр – это читаемый поток, который мы будем обрабатывать после получения HTTP-запроса. Затем мы отправим res
В качестве ответа, который, опять же, простой пилотный поток.
Затем, используя .on ()
Метод, мы читаем тело запроса в кусках 64 КБ и храните его в Тело
, вызванные данные
мероприятие.
Обратите внимание на использование Setuncoding ()
метод перед чтением от потока.
Таким образом, поток будет излучать строки, и он выделяет Буфер
объекты иначе. Хотя вы также можете выполнить этот разговор внутри данные
Обратный вызов события, если вы предпочитаете.
конец
Событие срабатывает, когда в читабельном потоке ничего не осталось читать. Мы поговорим о других полезных событиях позже в этой статье.
Теперь давайте послушаем сервер:
server.listen(1337);
Ударить http://localhost: 1337
, вы должны увидеть простой Здравствуйте, мир
Ответ с HTTP-сервера.
Поток трубопроводов
Использование потоковных труб мы можем напрямую трусить читаемые потоки к записи записи, не сохраняя буфер временно – поэтому мы можем сохранить пространство памяти.
Рассмотрим сценарий, в котором пользователь запросиет большой файл с сервера, и нет места памяти, чтобы загрузить его в память, или один и тот же файл запрашивается тысячами разных клиентов. В этом случае мы не можем прочитать содержание файла в память, а затем записывать его обратно к клиенту.
Это где труба
Метод полезен, поскольку мы будем трусить читаемый поток (запрос) в пирентный поток (ответ) и обслуживаете его пользователю, не удерживая его в буфере.
Во-первых, давайте сделаем это без использования потоков:
const fs = require('fs'); const server = require('http').createServer(); server.on('request', (req, res) => { fs.readFile('./video.mkv', (err, data) => { if (err) throw err; res.end(data); }); }); server.listen(1337);
Этот метод напрямую читает файл в память, используя .readfile ()
метод и отправляет его пользователю.
Откройте свой веб-браузер и перейдите в http://localhost: 1337
Вот что происходит за кулисами:
Теперь давайте обслуживаем видео с помощью потока:
const http = require('http'); const fs = require('fs'); const server = http.createServer((req, res) => { const src = fs.createReadStream('./video.mkv'); src.pipe(res); }); server.listen(1337);
В этом коде мы создали читаемый поток в файл и напрямую передаю его на ответ HTTP, поэтому, вместо того, чтобы загрузить его в память, вход с диска HDD непосредственно записан в сеть, не потребляя память.
Вот скриншот использования памяти при отправке файла с помощью потока:
Как вы можете видеть, что использование памяти слишком низкое по сравнению с первым методом.
Полезные события в потоке
Так как Поток
Класс наследует Eventemitter
Класс, каждый поток будет иметь свой тип событий, которые вы можете подписаться на использование Eventemitter
‘s на ()
метод. Это событие будет зависеть от типа потока.
События в читаемых потоках
данные
: Излучается, когда кусок данных читается из потока. По умолчанию чан будетБуфер
объект. Если вы хотите изменить его, вы можете использовать.setencoding ()
метод.Ошибка
.: Испускается, когда происходит ошибка во время чтения. Это может произойти, если запись Reature не может генерировать данные из-за некоторой внутренней ошибки или когда неверный кусок нажата в поток.конец
: Выпускается, когда в потоке больше нет данных.Закрыть
: Испускаемый, когда ресурс потока закрыт и указывает на то, что в будущем больше событий не будет выпущено.читаемый
: Выпускается, когда данные доступны в читаемом потоке для чтения.
События в запоресном потоках
Закрыть
: Испускаемый, когда ресурс потока закрыт и указывает на то, что в будущем больше событий не будет выпущено.Ошибка
.: Испускается, когда происходит ошибка во время чтения. Это может произойти, если reature Stream не может генерировать данные из-за некоторой внутренней ошибки или когда недействительные данные ловушки нажаты в поток.Готово
: Выпускается, когда все данные были покрашены из записи пирета.труба
: Излучается, когда писнутый поток работает на читаемый поток.unpipe
: Излучается, когда писнутый поток не работает от читаемого потока.
Заключение
В простых терминах потоки используются для чтения из ввода или записи в вывод последовательно. Большую часть времени потоки используются для чтения или записи из непрерывного источника или сравнительно большой.
Модуль потока – это родной модуль, который поставляется по умолчанию в Node.js. Поток
является примером Eventemitter
Класс, который обрабатывает события асинхронно в Node.js. Из-за их суперкласса потоки по своей природе насущены.
Трансформационные потоки Не было охвачено в этой статье, поскольку они оказывают свою собственную статью.
Исходный код этого проекта доступен на Github по-прежнему. Используйте это, чтобы сравнить свой код, если вы застряли вдоль учебника.
Если вы хотите больше информации о потоках и или на продвинутых знаниях, рекомендуется следовать за Официальная документация для потоков.