Node.js のストリームを理解する

青灯夜游
リリース: 2020-11-19 17:49:29
転載
2959 人が閲覧しました

Node.js のストリームを理解する

関連する推奨事項: 「nodejs チュートリアル

バックエンドの経験を持つほとんどの学生にとって、Stream オブジェクトは合理的で一般的なオブジェクトです。しかし、フロントエンドのクラスメートである Stream は、それほど当たり前のことではありません。github には、Stream とは何かを紹介する 9,000 個以上のスターが付いた記事もあります - stream-handbook (https://link.zhihu.com/?target=https: / /github.com/substack/stream-handbook)。 Streamをより深く理解するために、この記事をもとに簡単にまとめてみましょう。

ストリームとは

ストリームは Unix システムでは非常に一般的で重要な概念であり、用語的には入出力デバイスを抽象化したものです。

ls | grep *.js
ログイン後にコピー

スクリプトを作成するときに、このようなコードによく遭遇します。| を使用して 2 つのコマンドを接続し、前のコマンドの結果を次のコマンドとして使用します。のコマンドが渡されるため、データはパイプライン内の水のように送信されます。各コマンドはプロセッサのようなもので、データに対して何らかの処理を行うため、| は「パイプライン シンボル#」と呼ばれます。 ##」。

NodeJS のいくつかのタイプのストリーム

プログラムの観点から見ると、ストリームは

方向性データであり、フローの方向に応じて 3 つのタイプに分類できます

  • デバイスからプログラムへのフロー: 読み取り可能

  • デバイスへのプログラム フロー: 書き込み可能

  • 双方向: 二重、変換

NodeJS のストリーム操作は Stream モジュールにカプセル化されており、複数のコア モジュールからも参照されます。 Unix の哲学によれば、すべてはファイルであり、NodeJS でのほとんどのファイル処理はストリームを使用して、

  • 通常のファイル

  • デバイス ファイル ( stdin 、stdout)

  • ネットワーク ファイル (http、net)

見落としがちな知識ポイントがあります。NodeJS のすべてのストリームは、 EventEmitter のインスタンス。

小さな例

プログラムを書くときに、突然特定の設定ファイル

config.json を読み込む必要が生じます。このとき、## を簡単に分析します。

# データ : config.json の内容
  • # 方向 : デバイス (物理ディスク ファイル) -> NodeJS プログラム
  • #これを行うには、読み取り可能なストリームを使用する必要があります
const fs = require('fs');
const FILEPATH = '...';

const rs = fs.createReadStream(FILEPATH);
ログイン後にコピー

fs モジュールが提供する

createReadStream()

メソッドを使用して、読み取り可能なストリームを簡単に作成します。このとき、config.json のコンテンツは次から流れてきます。デバイスをプログラムに接続します。 fs は既に内部で Stream モジュールを参照し、それをカプセル化しているため、Stream モジュールを直接使用しません。 データを取得したら、それを処理する必要があります。たとえば、特定のパス DEST に書き込む必要があります。このとき、データがプログラムからデータに流れることを可能にする書き込み可能なストリームが必要です。デバイス。

const ws = fs.createWriteStream(DEST);
ログイン後にコピー

2 つのストリーム、つまり 2 つのデータ プロセッサがあるので、Unix のようなパイプ記号

|

を介してストリームをどのように接続すればよいでしょうか? NodeJS のパイプ シンボルは pipe() メソッドです。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const fs = require('fs'); const FILEPATH = '...'; const rs = fs.createReadStream(FILEPATH); const ws = fs.createWriteStream(DEST); rs.pipe(ws);</pre><div class="contentsignin">ログイン後にコピー</div></div>このように、ストリームを使用して単純なファイルコピー機能を実装しています。pipe()メソッドの実装原理については後述しますが、注意すべき点が1つあります。データはパイプされる必要があります。上流から下流へ、つまり読み取り可能なストリームから書き込み可能なストリームへパイプします。

データを処理する

上記の読み取り可能および書き込み可能なストリームをプロセッサーと呼びますが、実際には適切ではありません。なぜなら、何も処理しておらず、データを読み取って保存しているだけだからです。データ。

必要に応じて、ローカルの

package.json

ファイル内のすべての文字を小文字に変更し、同じディレクトリ内の package- lower.json ファイルに保存します。 現時点では、双方向ストリームを使用する必要があります。文字を小文字に変換することを特に処理するストリーム lower があると仮定します。その場合、記述されるコードはおそらく次のようになります

const fs = require('fs');

const rs = fs.createReadStream('./package.json');
const ws = fs.createWriteStream('./package-lower.json');

rs.pipe(lower).pipe(ws);
ログイン後にコピー

At Pipe() で接続されたストリームがプロセッサと呼ばれる理由がわかります。上記によると、パイプは読み取り可能なストリームから書き込み可能なストリームに到達する必要があります:

rs -> lower: lower はダウンストリームであるため、 lower は書き込み可能なストリームである必要があります
  • lower -> ws: 相対的に言えば、 lower はアップストリームであるため、 lower は読み取り可能なストリームである必要があります
  • これは少し理屈ですが、「The lower we need should be a bi-direction flow.」という条件を満たすことができます。duplex または transform の具体的な使用法については後で説明します。

もちろん、ASCII ストリームがあると仮定して、ASCII コードに変換する必要がある文字などの追加の処理アクションがある場合、コードは

rs.pipe(lower).pipe(acsii).pipe(ws);
ログイン後にコピー

同様に、 ascii も双方向ストリームである必要があります。この処理のロジックは非常に明確です。コードが明確であることに加えて、ストリームを使用する利点は何でしょうか?

ストリームを使用する理由

ユーザーがオンラインでビデオを視聴する必要があるシナリオがあります。HTTP リクエストを通じてユーザーに映画コンテンツを返すと仮定すると、コードは次のようになります。このように書かれています

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

http.createServer((req, res) => {
   fs.readFile(moviePath, (err, data) => {
      res.end(data);
   });
}).listen(8080);
ログイン後にコピー

这样的代码又两个明显的问题

  • 电影文件需要读完之后才能返回给客户,等待时间超长

  • 电影文件需要一次放入内存中,相似动作多了,内存吃不消

用流可以讲电影文件一点点的放入内存中,然后一点点的返回给客户(利用了 HTTP 协议的 Transfer-Encoding: chunked 分段传输特性),用户体验得到优化,同时对内存的开销明显下降

const http = require('http');

const fs = require('fs');

http.createServer((req, res) => {

   fs.createReadStream(moviePath).pipe(res);

}).listen(8080);
ログイン後にコピー

除了上述好处,代码优雅了很多,拓展也比较简单。比如需要对视频内容压缩,我们可以引入一个专门做此事的流,这个流不用关心其它部分做了什么,只要是接入管道中就可以了

const http = require('http');

const fs = require('fs');

const oppressor = require(oppressor);

http.createServer((req, res) => {

   fs.createReadStream(moviePath)

      .pipe(oppressor)

      .pipe(res);

}).listen(8080);
ログイン後にコピー

可以看出来,使用流后,我们的代码逻辑变得相对独立,可维护性也会有一定的改善,关于几种流的具体使用方式且听下回分解。

更多编程相关知识,请访问:编程视频课程!!

以上がNode.js のストリームを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:cnblogs.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!