1. Введение
В этой статье представлены основные методы разработки программ с использованием потоков Node.js.
<code> «У нас должно быть несколько способов подключения программ, таких как садовый шланг-свисание, неприятный сегмент, когда он становится необходимым для массажа данных больше. 11 октября 1964 г. </code>
Первым, кто вступил в контакт с потоком, было десятилетия практики, которая началась с раннего Unix, что доказало, что идеи потока могут просто разработать некоторые огромные системы. В UNIX поток реализуется через |; В узле, в качестве модуля встроенного потока, используются многие основные модули и трехпартийные модули. Как и Unix, основная операция потока узлов составляет .pipe (), и пользователи могут использовать механизм контрприкосновения для управления балансом между чтением и записи.
Поток может предоставить разработчикам унифицированный интерфейс, который может повторно использовать и контролировать баланс чтения и записи между потоками через абстрактные интерфейсы потока.
2. Зачем использовать поток
Ввод -вывод в узле является асинхронным, поэтому чтение и написание диска и сети требует чтения и записи данных с помощью функций обратного вызова. Ниже приведен простой код для сервера загрузки файла:
<code> var http = require ('http'); var fs = require ('fs'); var server = http.createserver (function (req, res) {fs.readfile (__ dirname + '/data.txt', function (err, data) {res.end (data);});});Эти коды могут реализовать необходимые функции, но служба должна кэшировать все данные файла в память перед отправкой данных файла. Если файл «data.txt» большой, а параллелизм большой, много памяти будет потрачено впустую. Поскольку пользователь должен подождать, пока весь файл не станет кэширован в памяти, прежде чем данные файла будут приняты, это приводит к очень плохим опыту пользователя. К счастью, оба параметра (req, res) являются потоком, поэтому мы можем использовать fs.createreadstream () вместо fs.readfile ():
<code> var http = require ('http'); var fs = require ('fs'); var server = http.createserver (function (req, res) {var stream = fs.createreadStream (__ dirname + '/data.txt'); stream.pipe (res);}); server.listen (8000);Метод .pipe () прослушивает события «данные» и «конец» fs.createreadstream (), так что файл «data.txt» не нуждается в кэшировании всего файла. После того, как подключение к клиенту завершено, блок данных может быть немедленно отправлен клиенту немедленно. Еще одним преимуществом использования .pipe () является то, что он может решить проблему чтения и написания дисбаланса, вызванного очень большой задержкой клиента. Если вы хотите сжать файл и отправить его, вы можете использовать трехпартийный модуль для его реализации:
<code> var http = require ('http'); var fs = require ('fs'); var oppressor = require ('hoppressor'); var server = http.createserver (funct '/data.txt'); stream.pipe (oppressor (req))Таким образом, файл сжимает браузер, который поддерживает GZIP и дефшит. Модуль угнетения обрабатывает все кодирование контента.
Поток делает разработку программ простыми.
3. Основные понятия
Есть пять основных потоков: читаемые, записываемые, преобразование, дуплекс и «классический».
3-1, труба
Все типы потокового использования .pipe () для создания входной и выходной пары, получите читаемый поток SRC и выводят его данные в DST с записи, следующим образом:
<code> src.pipe (dst) </code>
Метод .pipe (DST) возвращает поток DST, так что несколько .pipe () можно использовать последовательно, следующим образом:
<code> a.pipe (b) .pipe (c) .pipe (d) </code>
Функция такая же, как и следующий код:
<code> a.pipe (b); B.pipe (c); C.pipe (d); </code>
3-2. Читаемые потоки
Вызовив метод .pipe () прочитаемых потоков, вы можете написать данные читаемых потоков в потоку для записи, преобразования или дуплекса.
<code> readableStream.pipe (DST) </code>
1> Создать читаемый поток
Здесь мы создаем читаемый поток!
<code> var pertable = require ('Stream'). Readable; var rs = new Readable; rs.push ('beep'); rs.push ('boop/n'); rs.push (null); rs.pipe (process.stdout); $ node read0.jsbeep boop </code>Rs.push (NULL) уведомляет получателя данных, что данные были отправлены.
Обратите внимание, что мы не называли Rs.pipe (Process.stdout); Перед тем, как протолкнуть все данные в читаемый поток, но все данные в читабельный поток все еще полностью выводятся, потому что читаемый поток кэширует все нажатые данные, прежде чем приемник считывает данные. Но во многих случаях лучшим способом является то, чтобы нажать данные только в читабельный поток, когда данные получают запрошенные данные вместо кэширования всех данных. Давайте переписаем функцию ._read () ниже:
<code> var pertable = require ('Stream'). Readable; var rs = readable (); var c = 97; rs._read = function () {rs.push (string.fromcharcode (c ++)); if (c> 'z'.charcodeat (0)) rs.push (null);}; rs.pipe (process.stdout); read1.jsabcdefghijklmnopqrstuvwxyz </code>Приведенный выше код реализует переписывание метода _read (), чтобы продвигать данные в читабельный поток, только если получатель данных запрашивает данные. Метод _read () также может получать параметр размера, который указывает на запрошенный размер данных данных, но читаемый поток может игнорировать этот параметр по мере необходимости.
Обратите внимание, что мы также можем использовать util.inherits () для наследования читаемых потоков. Чтобы проиллюстрировать, что метод _read () вызывается только тогда, когда получатель данных запрашивает данные, мы делаем задержку при вталкивании данных в читаемый поток, следующим образом:
<code> var pertable = require ('Stream'). Readable; var rs = pertable (); var c = 97 - 1; rs._read = function () {if (c> = 'z'.charcodeat (0)) return rs.push (null); settimeout (function () {rs.push (string.fromchar 100);}; rs.pipe (process.stdout); process.on ('exit', function () {console.error ('/n_read () называется' + (c - 97) + 'times');}); process.stdout.on ('error', process.exit); </code>;При запуске программы со следующей командой мы обнаружили, что метод _read () был вызван только 5 раз:
<code> $ node read2.js | Head -c5abcde_read () Вызов 5 раз </code>
Причина использования таймера заключается в том, что система требует времени, чтобы отправить сигналы, чтобы информировать программу для закрытия трубопровода. Используйте Process.stdout.on ('error', fn), чтобы обрабатывать систему, отправляющую сигнал Sigpipe, потому что команда заголовка закрывает трубопровод, потому что это приведет к тому, что процесс. Если вы хотите создать читаемый поток, который можно нажать в любую форму данных, просто установите параметр ObjectMode на True при создании потока, например: Readable ({ObjectMode: true}).
2> читаемые данные потока
В большинстве случаев мы просто используем метод трубы для перенаправления данных читаемого потока в другую форму потока, но в некоторых случаях может быть более полезно для чтения данных непосредственно из читаемого потока. следующее:
<code> process.stdin.on ('redable', function () {var buf = process.stdin.read (); console.dir (buf);}); $ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | потребление узела0.js <buffer 0a = "" 61 = "" 62 = "" 63 = ""> <buffer 0a = "" 64 = "" 65 = "" 66 = ""> <буфер 0a = "" 67 = "" 68 = "69 =" "> null </buffer> </buffer> </buffer> </code> code> </cod> </cod> </cod> </cod> </cod> </cod>Когда в читаемом потоке есть данные, которые будут считываться, поток запустит событие «читаемого», так что метод .read () может быть вызван для чтения соответствующих данных. Когда нет данных, которые можно было бы прочитать в читаемом потоке, .Read () вернет NULL, так что вызов .Read () можно закончить и ждать следующего «читаемого» события. Вот пример использования .read (n) для чтения 3 байта каждый раз из стандартного ввода:
<code> process.stdin.on ('reteble', function () {var buf = process.stdin.read (3); console.dir (buf);}); </code>Запуск программы следующим образом показывает, что результаты выходных данных не завершены!
<code> $ (echo abc; Sleep 1; echo def; Sleep 1; echo ghi) | потребление узла1.js <буфер 61 = "" 62 = "" 63 = ""> <буфер 0a = "" 64 = "" 65 = ""> <буфер 0a = "" 66 = "" 67 = ""> </buffer> </buffer> </buffer> </code>
Это должно быть сделано для того, чтобы дополнительные данные были оставлены во внутреннем буфере потока, и нам нужно уведомить поток, который мы хотим прочитать больше данных. Читать (0) может достичь этого.
<code> process.stdin.on.on ('redemble', function () {var buf = process.stdin.read (3); console.dir (buf); process.stdin.read (0);}); </code>Результаты этого прогона следующие:
<code> $ (echo abc; Sleep 1; echo def; Sleep 1; echo ghi) | потребление узла2.js <buffer 0a = "" 64 = "" 65 = ""> <buffer 0a = "" 68 = "" 69 = ""> </buffer> </buffer> </code>
Мы можем использовать. Unshift () для изменения размера данных обратно на головку потоковой очереди данных, чтобы мы могли продолжать читать стасовые данные. Как и в следующем коде, стандартное входное содержимое будет выводиться по строке:
<code> var offset = 0; process.stdin.on ('reteble', function () {var buf = process.stdin.read (); if (! buf) return; for (; offset <buf.length; offset ++) {if (buf [offset] === 0x0a) {console.dir (buf.slice (0, offset). buf.slice (offset + 1); offset = 0; process.stdin.unshift (buf); return;}} process.stdin.unshift (buf);}); $ tail -n +50000/usr/share/dict/american -angshlish | голова -n10 | узлыКонечно, есть много модулей, которые могут реализовать эту функцию, такие как разделение.
3-3. записываемые потоки
Записные потоки могут использоваться только в качестве параметра назначения функции .pipe (). Следующий код:
<code> src.pipe (wriseableStream); </code>
1> Создать записи, который можно записать
Перепишите метод ._Write (Chunk, Enc, Next), чтобы принять данные из читаемого потока.
<code> var wriseble = require ('Stream'). writeble; var ws = writeable (); ws._write = function (chunk, enc, next) {console.dir (chunk); next ();}; process.stdin.pipe (ws); $ (echo beep; sleep 1; echo boop) | Узел write0.js <buffer 0a = "" 62 = "" 65 = "" 70 = ""> <buffer 0a = "" 62 = "" 6f = "" 70 = ""> </buffer> </buffer> </code>Первый параметр Chunk - это данные, записанные данным данных. Второй конец параметра является форматом кодирования данных. Третий параметр Next (ERR) уведомляет автора данных через функцию обратного вызова, что может быть записано больше времени. Если читаемый поток записывает строку, строка будет преобразована в буфер по умолчанию. Если параметр записи ({decodestrings: false}) устанавливается при создании потока, то преобразование не будет выполнено. Если данные записаны читабельным потоком, то вам нужно создать записи, который можно записать, таким образом
<code> writeble ({objectMode: true}) </code>2> Записать данные в потоку для записи
Вызовите метод.
<code> process.stdout.write ('beep boop/n'); </code>Вызов метода .end () уведомляет о записи, что данные были записаны для завершения.
<code> var fs = require ('fs'); var ws = fs.createwritestream ('message.txt'); ws.write ('beep'); settimeout (function () {ws.end ('boop/n');}, 1000); $ node witch1.js $ message.txtbeep boop </code>Если вам нужно установить размер буфера записи, который можно записать, то при создании потока вам необходимо установить opts.highwatermark, так что если данные в буфере превышают Opts.highwatermark, метод .write (data) вернет false. Когда буфер подходит для записи, писательский поток запустит событие «дренаж».
3-4. Классические потоки
Classic Streams - это более старый интерфейс, который впервые появился в версии Node 0.4, но все еще очень хорошо понять его принцип работы.
где. Когда поток зарегистрирован с событием «Data» обратно на функцию, поток будет работать в режиме старой версии, то есть будет использоваться старый API.
1> Классические читаемые потоки
Классическое событие читаемых потоков - это триггер событий. Если классические читаемые потоки имеют данные для чтения, он запускает событие «Данные». Когда данные будут прочитаны, событие «Конец» будет запускается. Метод .pipe () определяет, есть ли поток данных для чтения путем проверки значения потока. Читаемый. Вот пример печати букв AJ с использованием классических читаемых потоков:
<code> var stream = require ('stream'); var stream = new Stream; stream.readable = true; var c = 64; var iv = setInterval (function () {if (++ c> = 75) {clearInterval (iv); stream.emit ('end');} else stream Node classic0.jsabcdefghij </code>Если вы хотите прочитать данные из классического читаемого потока, зарегистрируйте функции обратного вызова двух событий «Данные» и «Конец», код выглядит следующим образом:
<code> process.stdin.on ('data', function (buf) {console.log (buf);}); process.stdin.on ('end', function () {console.log ('__ End __');}); $ (echo beep; sleep 1; echo boop) | Узел Classic1.js <buffer 0a = "" 62 = "" 65 = "" 70 = ""> <buffer 0a = "" 62 = "" 6f = "" 70 = ""> __ End __ </buffer> </buffer> </code>Следует отметить, что если вы используете этот метод для чтения данных, вы потеряете преимущества использования нового интерфейса. Например, когда вы записываете данные в поток с очень высокой задержкой, вам необходимо обратить внимание на баланс между чтением и написанием данных, в противном случае это приведет к кэшированию большого количества данных в памяти, что приведет к пустой трате большей памяти. Как правило, настоятельно рекомендуется использовать метод .pipe () потока, чтобы вам не приходилось сами слушать события «данные» и «конечно», и вам не нужно беспокоиться о проблеме несбалансированного чтения и письма. Конечно, вы также можете использовать его вместо того, чтобы слушать события «данные» и «конец» самостоятельно, например, следующий код:
<code> var через = require ('через'); process.stdin.pipe (через (write, end)); function write (buf) {console.log (buf);} function end () {console.log ('end __');} $ (echo beep; sleep 1; echo boop) | Узел через.Или вы также можете использовать Concat-Stream для кэширования содержимого всего потока:
<code> var concat = require ('concat-stream'); process.stdin.pipe (concat (function (body) {console.log (json.parse (body));})); $ echo '{"beep": "boop"}' | node concat.js {beep: 'boop'} </code>Конечно, если вам нужно выслушать события «данные» и «конец» самостоятельно, то вы можете использовать метод .pause (), чтобы приостановить классические читаемые потоки и продолжать запускать событие «данные», когда поток написания данных не подлежит записи. Подождите, пока данные о записи потока не будут записываются, прежде чем использовать метод .resume () уведомляет поток, чтобы продолжать запускать событие «данные» для продолжения чтения.
данные.
2> Классические письменные потоки
Классические письменные потоки очень просты. Есть только три метода: .Write (BUF), .END (BUF) и .destroy (). Параметр BUF метода .end (BUF) не является обязательным. Если вы выберете этот параметр, он эквивалентен потоку. Write (buf); Stream.end (). Следует отметить, что когда буфер потока заполнен, то есть поток не может быть записан. Метод записи (BUF) вернет false. Если поток снова можно записать, поток запустит сливное событие.
4. Преобразование
Преобразование - это поток, который фильтрует выход данных чтения.
5. Дуплекс
Дуплексный поток-это двусторонний поток, который можно прочитать или записано. Например, ниже - дуплексный поток:
<code> a.pipe (b) .pipe (a) </code>
Приведенное выше контент представляет собой руководство пользователя потока данных Nodejs потока, введенное вам редактором. Я надеюсь, что это будет полезно для вас!