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

Node.js Потоки

Узнайте, для чего нужны потоки, почему они так важны и как их использовать.

  • Что такое потоки
  • Почему потоки
  • Пример потока
  • труба()
  • API-интерфейсы узлов на основе потоков
  • Различные типы потоков
  • Как создать читаемый поток
  • Как создать поток с возможностью записи
  • Как получить данные из читаемого потока
  • Как отправить данные в поток с возможностью записи
  • Сигнализирующий о том, что вы завершили поток, доступный для записи пишу

Что такое потоки

Потоки – это одна из фундаментальных концепций, которая обеспечивает Node.js приложения.

Они являются способом эффективной обработки файлов для чтения/записи, сетевых коммуникаций или любого вида сквозного обмена информацией.

Потоки не являются концепцией, уникальной для Node.js . Они были введены в операционную систему Unix десятилетия назад, и программы могут взаимодействовать друг с другом, передавая потоки через оператор канала ( |).

Например, традиционным способом, когда вы указываете программе прочитать файл, файл считывается в память от начала до конца, а затем вы его обрабатываете.

Используя потоки, вы читаете его по частям, обрабатывая его содержимое, не сохраняя все это в памяти.

В Node.js поток модуль обеспечивает основу, на которой строятся все потоковые API.

Почему потоки

Потоки в основном обеспечивают два основных преимущества при использовании других методов обработки данных:

  • Эффективность работы памяти : вам не нужно загружать большие объемы данных в память, прежде чем вы сможете их обработать
  • Эффективность по времени : требуется намного меньше времени, чтобы начать обработку данных, как только они у вас появятся, вместо того, чтобы ждать, пока вся полезная нагрузка данных будет доступна для запуска.

Пример потока

Типичным примером является чтение файлов с диска.

Используя модуль Node fs , вы можете прочитать файл и передать его по протоколу HTTP, когда будет установлено новое соединение с вашим http-сервером:

const http = require('http')
const fs = require('fs')

const server = http.createServer(function (req, res) {
  fs.readFile(__dirname + '/data.txt', (err, data) => {
    res.end(data)
  })
})
server.listen(3000)

ReadFile() считывает полное содержимое файла и вызывает функцию обратного вызова, когда это будет сделано.

res.end(данные) в обратном вызове вернет содержимое файла HTTP-клиенту.

Если файл большой, то операция займет совсем немного времени. Здесь то же самое написано с использованием потоков:

const http = require('http')
const fs = require('fs')

const server = http.createServer((req, res) => {
  const stream = fs.createReadStream(__dirname + '/data.txt')
  stream.pipe(res)
})
server.listen(3000)

Вместо того чтобы ждать, пока файл будет полностью прочитан, мы начинаем передавать его в потоковом режиме на HTTP-клиент, как только у нас есть часть данных, готовых к отправке.

труба()

В приведенном выше примере используется строка stream.pipe(res) : метод pipe() вызывается в файловом потоке.

Что делает этот код? Он берет источник и передает его в пункт назначения.

Вы вызываете его в исходном потоке, поэтому в этом случае поток файлов передается в HTTP-ответ.

Возвращаемое значение метода pipe() является целевым потоком, что является очень удобной вещью, которая позволяет нам связывать несколько вызовов pipe() , например:

src.pipe(dest1).pipe(dest2)

Эта конструкция такая же, как выполнение

src.pipe(dest1)
dest1.pipe(dest2)

API-интерфейсы узлов на основе потоков

Благодаря своим преимуществам многие Node.js основные модули обеспечивают собственные возможности обработки потоков, в первую очередь:

  • process.стандартный интерфейс возвращает поток, подключенный к стандартному интерфейсу
  • process.стандартный вывод возвращает поток, подключенный к стандартному выводу
  • process.stderr возвращает поток, подключенный к стандерр
  • fs.createReadStream() создает читаемый поток в файл
  • fs.createReadStream() создает читаемый поток в файл ()
  • создает поток с возможностью записи в файл net.connect()
  • инициирует потоковое соединение http.запрос()
  • возвращает экземпляр http. Класс ClientRequest, представляющий собой поток с возможностью записи zlib.createGzip()
  • сжимать данные с помощью gzip (алгоритм сжатия) в поток zlib.createGunzip()
  • распаковать поток gzip. zlib.createDeflate()
  • сжимать данные с помощью deflate (алгоритм сжатия) в поток zlib.createInflate()

Различные типы потоков

Существует четыре класса потоков:

  • Читаемый : поток, из которого вы можете передавать, но не в который вы можете передавать (вы можете получать данные, но не отправлять их в него). Когда вы помещаете данные в читаемый поток, они буферизуются до тех пор, пока потребитель не начнет считывать данные.
  • Доступный для записи : поток, в который вы можете передавать, но не из которого (вы можете отправлять данные, но не получать от него)
  • Дуплекс : поток, в который вы можете как входить, так и выходить, в основном представляет собой комбинацию читаемого и записываемого потока
  • Преобразование : поток преобразования аналогичен дуплексу, но вывод является преобразованием его входного сигнала

Как создать читаемый поток

Мы получаем читаемый поток из модуля stream /и инициализируем его

const Stream = require('stream')
const readableStream = new Stream.Readable()

Теперь, когда поток инициализирован, мы можем отправлять в него данные:

readableStream.push('hi!')
readableStream.push('ho!')

Как создать поток с возможностью записи

Чтобы создать записываемый поток, мы расширяем базовый Записываемый объект и реализуем его метод _write().

Сначала создайте объект потока:

const Stream = require('stream')
const writableStream = new Stream.Writable()

затем реализуйте _write :

writableStream._write = (chunk, encoding, next) => {
    console.log(chunk.toString())
    next()
}

Теперь вы можете передавать читаемый поток в:

process.stdin.pipe(writableStream)

Как получить данные из читаемого потока

Как мы считываем данные из читаемого потока? Использование потока с возможностью записи:

const Stream = require('stream')

const readableStream = new Stream.Readable()
const writableStream = new Stream.Writable()

writableStream._write = (chunk, encoding, next) => {
    console.log(chunk.toString())
    next()
}

readableStream.pipe(writableStream)

readableStream.push('hi!')
readableStream.push('ho!')

Вы также можете использовать читаемый поток напрямую, используя событие читаемый :

readableStream.on('readable', () => {
  console.log(readableStream.read())
})

Как отправить данные в поток с возможностью записи

Использование метода stream write() :

writableStream.write('hey!\n')

Сигнализирующий о том, что вы завершили поток, доступный для записи пишу

Используйте метод end() :

const Stream = require('stream')

const readableStream = new Stream.Readable()
const writableStream = new Stream.Writable()

writableStream._write = (chunk, encoding, next) => {
    console.log(chunk.toString())
    next()
}

readableStream.pipe(writableStream)

readableStream.push('hi!')
readableStream.push('ho!')

writableStream.end()

Оригинал: “https://flaviocopes.com/nodejs-streams/”