/
64mb
/
node-labs-ru
Обзор
Документация
Войти
/
64mb
/
node-labs-ru
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
master
streams.html
228 строк
27 KB
Georgy Malkov
init
03 ноя 2021, 12:02
03 ноя 2021, 12:02
49d714e
Код
Авторство
О чём код?
<!DOCTYPE html> <html> <!-- Mirrored from www.nodelabs.org/streams.html by HTTrack Website Copier/3.x [XR&CO'2014], Mon, 04 Sep 2017 18:01:57 GMT --> <!-- Added by HTTrack --><meta http-equiv="content-type" content="text/html;charset=utf-8" /><!-- /Added by HTTrack --> <head> <title>Потоки - Node Labs</title> <link href="css/post.css" rel="stylesheet" type="text/css"/> <link href="css/pygments.css" rel="stylesheet" type="text/css"/> <link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700|Droid+Sans+Mono' rel='stylesheet' type='text/css' /> <script src="../ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script src="../cdn.jsdelivr.net/jquery.cookie/1.3.1/jquery.cookie.js"></script> <script src="../nodelabs.herokuapp.com/socket.io/socket.io.html"></script> <script src="js/unlock.js"></script> <script type="text/javascript"> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','../www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-35011668-1', 'nodelabs.org'); ga('require', 'linkid', 'linkid.html'); ga('send', 'pageview'); </script> </head> <body> <div id="header"> <a href="index.html" title="Take me home!"><img src="css/img/logotype_dark.png" /></a> </div> <h1 id="streams">Потоки</h1> <p>Потоки - одна из самых удивительных особенностей Node. Однако, это не новость. *nix системы, использующие I/O потоки для перемещения данных из одного процесса в другой.</p> <h2 id="read-streams">Чтение потоков</h2> <p>Первый поток, который мы обсудим, представляет собой поток чтения. Как вы могли ожидать, этот поток поддерживает только чтение. Давайте рассмотрим пример.</p> <p>Начнем с создания файла с именем <code>example.txt</code> и добавим любое содержимое, которое вам нравится. Создайте еще один файл <code>readable.js</code> и добавьте следующее:</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'fs'</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">rs</span> <span class="o">=</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">createReadStream</span><span class="p">(</span><span class="s1">'./example.txt'</span><span class="p">);</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'data'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="p">});</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'end'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'end'</span><span class="p">);</span> <span class="p">});</span></code></pre></div> <p>Теперь, когда мы использовали читаемый поток, напишем наш собственный..</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">Readable</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'stream'</span><span class="p">).</span><span class="nx">Readable</span><span class="p">;</span> <span class="kd">var</span> <span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'util'</span><span class="p">);</span> <span class="nx">util</span><span class="p">.</span><span class="nx">inherits</span><span class="p">(</span><span class="nx">TeamStream</span><span class="p">,</span> <span class="nx">Readable</span><span class="p">);</span> <span class="kd">function</span> <span class="nx">TeamStream</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">Readable</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">best_sports_programs</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'K-State Football'</span><span class="p">,</span> <span class="s1">'K-State Basketball'</span><span class="p">,</span> <span class="s1">'K-State Baseball'</span><span class="p">];</span> <span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">this</span><span class="p">.</span><span class="nx">_read</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">program</span> <span class="o">=</span> <span class="nx">best_sports_programs</span><span class="p">[</span><span class="nx">i</span><span class="o">++</span><span class="p">];</span> <span class="k">this</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">program</span> <span class="o">||</span> <span class="kc">null</span><span class="p">);</span> <span class="p">}</span> <span class="p">};</span> <span class="kd">var</span> <span class="nx">rs</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">TeamStream</span><span class="p">();</span> <span class="kd">var</span> <span class="nx">received</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'data'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="nx">received</span><span class="o">++</span><span class="p">;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="k">if</span> <span class="p">(</span><span class="nx">received</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'pausing for some time'</span><span class="p">);</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">pause</span><span class="p">();</span> <span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">resume</span><span class="p">();</span> <span class="p">},</span> <span class="mi">3000</span><span class="p">);</span> <span class="p">}</span> <span class="p">});</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'end'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'ended'</span><span class="p">);</span> <span class="p">});</span></code></pre></div> <p>В этом примере мы узнаем несколько разных вещей. Во-первых мы созданим новый читаемый поток. Фунция <code>TeamStream</code> наследует прототип из ядра Node <code>ReadableStream</code> и в этом конструкторе вызывает <code>ReadableStream</code>. Мы должны вызвать конструктор основной реализации, чтобы выполнить необходимую инициализацию нашего потока. Мы должны внедрить внутренний метод <code>_read</code> который вызывается для каждого запроса на чтение. В этом примере первый запрос на чтение выдается всякий раз, когда мы подписываемся на событие <code>'data'</code>. Есть и другие способы сделать это, что мы рассмотрим далее.</p> <p>В этом примере вы заметите, что мы можем контролировать поток данных из читаемого потока через <code>pause</code> и <code>resume</code>. Это невероятно важно, чтобы ваше приложение не отставало от входящих данных и получало данные только при необходимости.</p> <p>В приведенном выше примере данные считываются буфером. Однако у нас есть более точный контроль над тем, сколько данных мы получаем через метод <code>read</code>. Следующий пример даст вам представление о серии событий, возникающих при чтении из потока, который может предоставлять данные в разное время. Это именно та ситуация, когда дело касается сетевых подключений. Не стесняйтесь копировать и вставлять этот фрагмент. Изучите выход и поймите цепочку событий, прежде чем двигаться дальше.</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">Readable</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'stream'</span><span class="p">).</span><span class="nx">Readable</span><span class="p">;</span> <span class="kd">var</span> <span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'util'</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">log</span> <span class="o">=</span> <span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">startTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span> <span class="k">return</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">msg</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">now</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'+'</span> <span class="o">+</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">((</span><span class="nx">now</span> <span class="o">-</span> <span class="nx">startTime</span><span class="p">)</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">)</span> <span class="o">+</span> <span class="s1">' '</span> <span class="o">+</span> <span class="nx">msg</span><span class="p">);</span> <span class="p">};</span> <span class="p">})();</span> <span class="nx">util</span><span class="p">.</span><span class="nx">inherits</span><span class="p">(</span><span class="nx">LetterStream</span><span class="p">,</span> <span class="nx">Readable</span><span class="p">);</span> <span class="kd">function</span> <span class="nx">LetterStream</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">Readable</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">letters</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'aaaaaa'</span><span class="p">,</span> <span class="s1">'bbbbbb'</span><span class="p">,</span> <span class="s1">'cccccc'</span><span class="p">,</span> <span class="s1">'dddddd'</span><span class="p">];</span> <span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">this</span><span class="p">.</span><span class="nx">_read</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'Internal read called.'</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">letter</span> <span class="o">=</span> <span class="nx">letters</span><span class="p">[</span><span class="nx">i</span><span class="o">++</span><span class="p">];</span> <span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">></span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">that</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span> <span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'Pushing data async.'</span><span class="p">);</span> <span class="nx">that</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">letter</span><span class="p">);</span> <span class="p">},</span> <span class="mi">2000</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'Pushing data.'</span><span class="p">);</span> <span class="k">this</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">letter</span> <span class="o">||</span> <span class="kc">null</span><span class="p">);</span> <span class="p">}</span> <span class="p">};</span> <span class="p">};</span> <span class="kd">var</span> <span class="nx">rs</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">LetterStream</span><span class="p">();</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'end'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'End'</span><span class="p">);</span> <span class="p">});</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'readable'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'Stream is readable'</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">c</span><span class="p">;</span> <span class="k">while</span> <span class="p">(</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">rs</span><span class="p">.</span><span class="nx">read</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span> <span class="p">{</span> <span class="nx">log</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">toString</span><span class="p">());</span> <span class="p">}</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'Reached end of readable data available'</span><span class="p">);</span> <span class="p">});</span> <span class="nx">log</span><span class="p">(</span><span class="s1">'Reached end of program. It\'s now alive because of async callbacks pending.'</span><span class="p">);</span></code></pre></div> <p>Мы успешно прочитали 2 байта из нашего базового потока с каждой итерацией цикла. Несмотря на количество вызовов в <code>read</code>, мы только вызываем нашу внутреннюю функцию, когда нужны новые данные.</p> <h2 id="write-stream">Запись потоков</h2> <p>Примером использования записи потоков являются HTTP-ответы или стандартный вывод. Как <code>ReadableStream</code>, <code>WritableStream</code> имеет встроенный механизм ограничения скорости. Эти потоки осведомлены о том, когда базовый буфер был сброшен и предоставляют вызывающей стороне эту информацию. Это очень полезно, так что вы не видите больше, чем клиент может обрабатывать. Если клиент не может принять информацию достаточно быстро, он будет буферизован в памяти. Давайте рассмотрим простой пример широко используемого потока записи. Откроем node REPL и введем следующее:</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s1">'Hello World'</span><span class="p">);</span></code></pre></div> <p>Обратите внимание, что REPL вывел Hello World и результат вызова метода <code>true</code>.Возвращаемое значение указывает, можно ли немедленно сбросить буфер. Если возвращаемое значение является ложным, это означает, что данные должны быть буферизованы в памяти и позже будут сброшены. Истина означает, что данные были немедленно записаны и не буферизованы.</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">WritableStream</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'stream'</span><span class="p">).</span><span class="nx">Writable</span><span class="p">;</span> <span class="c1">// Настраивая HighWaterMark на 0 мы говорим, что базовый буфер необходимо немедленно очистить.</span> <span class="kd">var</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WritableStream</span><span class="p">({</span> <span class="nx">highWaterMark</span><span class="o">:</span> <span class="mi">0</span><span class="p">});</span> <span class="nx">ws</span><span class="p">.</span><span class="nx">_write</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">enc</span><span class="p">,</span> <span class="nx">cb</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Если в опциях не указано иное, выполняется строка, которую мы записываем дальше</span> <span class="c1">// этот файл преобразуется в буфер.</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'Received'</span><span class="p">,</span> <span class="nx">data</span><span class="p">);</span> <span class="nx">setTimeout</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span> <span class="nx">enc</span><span class="p">,</span> <span class="nx">cb</span><span class="p">);</span> <span class="p">},</span> <span class="mi">1000</span><span class="p">);</span> <span class="p">};</span> <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">ws</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s1">'This should be buffered\n'</span><span class="p">);</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'write return value'</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span> <span class="c1">//Мы можем получить уведомление, когда базовый буфер был сброшен с помощью обратного вызова</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">ws</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s1">'This will also be buffered\n'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'We were notified about this buffer being flushed.'</span><span class="p">);</span> <span class="p">});</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'write (2) return value'</span><span class="p">,</span> <span class="nx">result</span><span class="p">);</span></code></pre></div> <h2 id="pipe-streams-together">Pipe потоки вместе</h2> <p>Много похвалы уделяется node от сообщества за предоставление чрезвычайно простого интерфейса для объединения потоков вместе, используя <code>pipe</code>. Вы уже знаете, что ОС *nix обеспечивают возможность подключения стандартного вывода одного процесса к стандартным входам другого, используя <code>|</code>. Давайте посмотрим, как мы можем принять наш стандартный ввод и направить его в поток выходных процессов..</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">process</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">pipe</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">);</span></code></pre></div> <p>Мы можем протестировать это, разместив вышеуказанное содержимое в файле pipe.js и выполнив следующую команду оболочки.</p> <div class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">echo</span> <span class="s1">'This is going to be piped out'</span> <span class="p">|</span> node pipe.js</code></pre></div> <p>Насколько это было легко! Если бы у нас не было <code>pipe</code>, то вот как мы выполнили бы ту же задачу. Вы можете видеть, что pipe много заботится о нас. То, чего вы не видите в этом примере, состоит в том, что<code>pipe</code> автоматически обрабатывает противодавление.</p> <div class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">process</span><span class="p">.</span><span class="nx">stdin</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'data'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span> <span class="p">});</span></code></pre></div> <div id="next"> <div class="continue"> <a href="deploying.html"> <!-- Please don't just skip through these, actually do the labs! --> Так держать! Перейдите к следующей ЛР. <span>Настройка готового процесса Node.js</span> </a> </div> </div> <div id="footer"> <p>Labs created by <a href="https://twitter.com/joeandaverde">@joeandaverde</a></p> <p>Учебный материал переведен <a href="https://t.me/Rat_Z">@Rat_Z</a> и <a href="https://t.me/Alex_Ebenrode">@Alex_Ebenrode</a></p> </div> </body> <!-- Mirrored from www.nodelabs.org/streams.html by HTTrack Website Copier/3.x [XR&CO'2014], Mon, 04 Sep 2017 18:01:58 GMT --> </html>