ホームページ >ウェブフロントエンド >jsチュートリアル >Nodejs の書き込み可能なストリームとは何ですか?使い方

Nodejs の書き込み可能なストリームとは何ですか?使い方

青灯夜游
青灯夜游転載
2020-11-23 17:49:303346ブラウズ

Nodejs の書き込み可能なストリームとは何ですか?使い方

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

書き込み可能なストリームとは

書き込み可能な Aストリームは、デバイスに流れるデータの抽象化です。上流から流れるデータを消費するために使用されます。データは、書き込み可能なストリーム プログラムを通じてデバイスに書き込むことができます。一般的に使用されるのは、ローカル ディスク ファイルまたは TCP や HTTP などのネットワーク応答です。

前に使用した例を見てください。

process.stdin.pipe(process.stdout);

*process.stdout* は書き込み可能なストリームであり、プログラムは読み取り可能なストリーム process.stdin 入力によって渡されたデータを書き込みます。標準出力デバイス。読み取り可能なストリームを理解することに基づいて書き込み可能なストリームを理解することは非常に簡単です。ストリームは方向性のあるデータであり、読み取り可能なストリームがデータ ソース、書き込み可能なストリームが宛先、中間のパイプライン リンクがデータです。双方向ストリーム。

書き込み可能なストリームは、

書き込み可能なストリーム インスタンスの **write() ** メソッドを呼び出して、書き込み可能なストリームにデータを書き込みます

const fs = require('fs');
const rs = fs.createReadStream('./w.js');
const ws = fs.createWriteStream('./copy.js');

rs.setEncoding('utf-8');
rs.on('data', chunk => {
  ws.write(chunk);
});

前述したように、読み取り可能ストリームのデータ イベントをリッスンすると、読み取り可能ストリームがフロー モードになり、コールバック イベントで書き込み可能ストリームの write() メソッドを呼び出して、データが書き込み可能ストリームに書き込まれます。抽象デバイス、つまり現在のディレクトリ内の copy.js ファイル内。

write() メソッドには 3 つのパラメータ

  • #chunk {String| Buffer} があり、書き込まれるデータを示します
  • # #coding
  • 書き込むデータが文字列の場合、エンコーディングを設定できます
  • callback
  • データ書き込み後のコールバック関数
カスタム書き込み可能ストリーム

カスタム読み取り可能ストリームと同様、単純なカスタム書き込み可能ストリームには 2 つの手順のみが必要です

ストリーム モジュールの
    Writable
  1. クラス#を継承します##実装#_write()
  2. メソッド
  3. # シンプルな書き込み可能ストリームを実装し、書き込み可能ストリームに渡されたデータを大文字化した後、標準出力デバイスに出力します。 (ローカル ディスク ファイルへの書き込みがより良い例かもしれませんが、fs 操作が多すぎて面倒なので、怠けましょう。標準出力デバイスへの書き込みも書き込み動作です)
  4. const Writable = require('stream').Writable
    
    class OutputStream extends Writable {
        _write(chunk, enc, done) {
            // 转大写之后写入标准输出设备
            process.stdout.write(chunk.toString().toUpperCase());
            // 此处不严谨,应该是监听写完之后才调用 done
            process.nextTick(done);
        }
    }
    
    module.exports = OutputStream;
は、最終的な書き込み可能ストリームによって公開される write() メソッドと同じです。_write() メソッドには 3 つのパラメータがあり、同様の機能があります。

chunk
    書き込まれたデータは大きいです。 decodeStrings が false に設定されていない限り、一部の時間はバッファーです
  • encoding
  • データが文字列の場合は、エンコーディングを設定できます。バッファーまたはオブジェクト モードはそれを無視します
  • callback
  • データ書き込み後のコールバック関数は、次のデータのストリームを通知できます; エラーが発生した場合、エラーパラメータを設定することもできます
  • もちろん、 _writev() メソッドも実装されていますが、このメソッドはスタック書き込みキューによってのみ呼び出されるので、実装する必要はありません。

書き込み可能なストリームのインスタンス化

書き込み可能なストリーム クラスを作成したら、それをインスタンス化して使用できます。書き込み可能なストリームをインスタンス化するときは、いくつかのオプションがあります。これを理解すると、後で使用する知識を理解するのに役立ちます

objectMode
  • デフォルトは false です。これを true に設定すると、writable.write() メソッドは次のようになります。文字列を書き込むだけではありません バッファに加えて、任意の JavaScript オブジェクトを書き込むことができます。非常に便利なオプションです。後で変換ストリームを紹介するときに詳しく説明します。highWaterMark
  • 毎回書き込まれるデータの最大量、デフォルト値バッファは 16kb、objectMode デフォルト値は 16decodeStrings
  • 受信データをバッファに変換するかどうか、デフォルトは trueこのようにすると、_write() メソッドで渡されるパラメーターの意味がより明確になり、後で紹介するバック プレッシャー メカニズムを理解するのに役立ちます。

イベント

読み取り可能なストリームと同様に、書き込み可能なストリームにも、一般的に使用されるイベントがいくつかあります。読み取り可能なストリームの基礎を備えているため、理解するのは比較的簡単です

pipe
    読み取り可能ストリームが Pipe() メソッドを呼び出してデータを書き込み可能ストリームに送信すると、書き込み可能ストリームのパイプ イベントがトリガーされます
  • unpipe
  • 読み取り可能ストリームが unpipe() メソッドを呼び出してデータ転送を削除すると、書き込み可能ストリームの unpipe イベントがトリガーされます。
  • これら 2 つのイベントは、次の目的で使用されます。書き込み可能なストリームデータが来る、または途切れるという通知は、通常の状況ではほとんど使用されません。

writeable.write()

このメソッドには bool 戻り値があり、前述の

highWaterMark のように、書き込む必要のあるデータが、 writable stream この時、データは一気に書き込まれず、一部のデータが残りますが、このとき writeable.write() は false を返し、処理可能であれば、 return true

drain
以前に取り残されたデータがあった場合、つまり writeable.write() が false を返した場合にトリガーされます。消化期間の後、データのバックログが処理されますそして新しいデータを書き続けることができます (排水の本来の目的) それは排水と枯渇です、非常に鮮やかです)

除了 write() 方法可写流还有一个常用的方法 end(),参数和 write() 方法相同,但也可以不传入参数,表示没有其它数据需要写入,可写流可以关闭了。

finish 当调用 writable.end() 方法,并且所有数据都被写入底层后会触发 finish 事件

同样出现错误后会触发 error 事件

back pressure

了解了这些事件,结合上之前提到的可读流的一些知识,我们就能探讨一些有意思的话题了。在最开始我们提到过用流相对于直接操作文件的好处之一是不会把内存压爆,那么流是怎么做到的呢?

最开始我们可能会想到因为流不是一次性把所有数据载入内存处理,而是一边读一边写。但我们知道一般读取的速度会远远快于写入的速度,那么 pipe()  方法是怎么做到供需平衡的呢?

回忆一些基础知识,我们自己来实现一下 pipe() 方法的核心原理

  1. 可读流有流动和暂停两种模式,可以通过 **pause() resume() **方法切换
  2. 可写流的 **write() **方法会返回是否能处理当前的数据,每次可以处理多少是 hignWatermark 决定的
  3. 当可写流处理完了积压数据会触发 drain 事件

我们可以利用这三点来做到数据读取和写入的同步,还是使用之前的例子,但为了使消费速度降下来,我们各一秒再通知完成

class OutputStream extends Writable {
    _write(chunk, enc, done) {
        // 转大写之后写入标准输出设备
        process.stdout.write(chunk.toString().toUpperCase());
        // 故意延缓通知继续传递数据的时间,造成写入速度慢的现象
        setTimeout(done, 1000);
    }
}

我们使用一下自定义的两个类

const RandomNumberStream = require('./RandomNumberStream');
const OutputStream = require('./OutputStream');

const rns = new RandomNumberStream(100);
const os = new OutputStream({
    highWaterMark: 8 // 把水位降低,默认16k还是挺大的
});

rns.on('data', chunk => {
    // 当待处理队列大于 highWaterMark 时返回 false
    if (os.write(chunk) === false) { 
        console.log('pause');
        rns.pause(); // 暂停数据读取
    }
});

// 当待处理队列小于 highWaterMark 时触发 drain 事件
os.on('drain', () => {
    console.log('drain')
    rns.resume(); // 恢复数据读取
});

结合前面的三点和注释很容易看懂上面代码,这就是 pipe() 方法起作用的核心原理。数据的来源的去向我们有了大概了解,后面可以开始介绍数据的加工

  • duplex
  • transform

更多编程相关知识,请访问:编程学习课程!!

以上がNodejs の書き込み可能なストリームとは何ですか?使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。