- Что такое потоки
- Почему потоки
- Пример потока
- труба()
- 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/”