Heim >Web-Frontend >js-Tutorial >Was ist ein beschreibbarer Stream in Nodejs? Wie zu verwenden

Was ist ein beschreibbarer Stream in Nodejs? Wie zu verwenden

青灯夜游
青灯夜游nach vorne
2020-11-23 17:49:303346Durchsuche

Was ist ein beschreibbarer Stream in Nodejs? Wie zu verwenden

Verwandte Empfehlungen: „nodejs-Tutorial

Was ist ein beschreibbarer Stream?

Beschreibbarer Stream ist eine Abstraktion des Datenflusses zum Gerät, der zum Verbrauchen von Daten verwendet wird, die vom Upstream durch das beschreibbare Stream-Programm fließen Beim Schreiben von Daten auf das Gerät handelt es sich normalerweise um eine lokale Festplattendatei oder eine Netzwerkantwort wie TCP oder HTTP.

Schauen Sie sich ein Beispiel an, das bereits verwendet wurde

process.stdin.pipe(process.stdout);

*process.stdout* ist ein beschreibbarer Stream. Das Programm schreibt die vom lesbaren Stream Process.stdin übergebenen Daten auf das Standardausgabegerät. Es ist sehr einfach, den beschreibbaren Stream auf der Grundlage des Verständnisses des lesbaren Streams zu verstehen. Ein Stream besteht aus gerichteten Daten, wobei der lesbare Stream die Datenquelle, der beschreibbare Stream das Ziel und die Pipeline-Verbindung in der Mitte eine bidirektionale ist Strom.

Beschreibbaren Stream verwenden

Rufen Sie die Methode **write()** der Instanz des beschreibbaren Streams auf, um Daten in den beschreibbaren Stream zu schreiben.

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);
});

Wie bereits erwähnt, wird das Datenereignis des lesbaren Streams überwacht Um den lesbaren Stream in den Fließmodus zu versetzen, rufen wir im Rückrufereignis die write()-Methode des beschreibbaren Streams auf, sodass die Daten auf das Gerät der beschreibbaren Stream-Abstraktion geschrieben werden, bei dem es sich um die Datei copy.js im aktuellen Verzeichnis handelt. Die

write()-Methode hat drei Parameter

  • chunk {String|. Buffer}, die die zu schreibenden Daten darstellen
  • Codierung Wenn die geschriebenen Daten eine Zeichenfolge sind, kann die Codierung festgelegt werden
  • Rückruf Die Rückruffunktion nach dem Schreiben der Daten

Benutzerdefinierter beschreibbarer Stream

Ein einfacher benutzerdefinierter beschreibbarer Stream erfordert nur zwei Schritte

  1. Erbt die Writable-Klasse des Stream-Moduls
  2. Implementieren Sie die Methode _write()

Lassen Sie uns einen einfachen beschreibbaren Stream implementieren, die in den beschreibbaren Stream übergebenen Daten in Großbuchstaben umwandeln und sie dann auf dem Standardausgabegerät ausgeben (ein besseres Beispiel könnte das Schreiben auf die lokale Festplatte sein). Datei, aber es sind zu viele fs-Vorgänge erforderlich, was problematisch ist. Das Schreiben auf das Standardausgabegerät ist ebenfalls ein Schreibverhalten Sind drei Parameter, ist die Funktion ähnlich Puffer- oder Objektmodus werden ignoriert

Rückruf
    Die Rückruffunktion kann den Stream über die nächsten Daten informieren, wenn ein Fehler auftritt. Sie können auch einen Fehlerparameter festlegen
  • Natürlich gibt es tatsächlich einen Die Methode _writev() kann implementiert werden. Diese Methode wird nur von festsitzenden Schreibwarteschlangen aufgerufen und kann möglicherweise nicht implementiert werden.
  • Instanziieren eines beschreibbaren Streams
  • Nachdem wir eine beschreibbare Stream-Klasse haben, können wir sie instanziieren und verwenden. Beim Instanziieren eines beschreibbaren Streams stehen uns mehrere Optionen zur Auswahl. Knowledge
objectMode

Der Standardwert ist false. Nachdem die Methode writable.write() auf true gesetzt wurde, kann sie zusätzlich zu String und Puffer jedes beliebige JavaScript-Objekt schreiben. Eine sehr nützliche Option, die später bei der Einführung des Transformationsstreams ausführlich vorgestellt wird

decodeStrings

Konvertieren Sie die eingehenden Daten in Puffer, der Standardwert ist true
  • Auf diese Weise können wir die Bedeutung der von der _write()-Methode übergebenen Parameter klarer erkennen und es wird für das Verständnis hilfreich sein der später eingeführte Gegendruckmechanismus.
  • Ereignisse
  • Wie lesbare Streams verfügen auch beschreibbare Streams über mehrere häufig verwendete Ereignisse. Mit der Grundlage lesbarer Streams ist es relativ einfach zu verstehen
  • pipe Wenn ein lesbarer Stream „pipe()“ aufruft Wenn die Methode Daten an den beschreibbaren Stream überträgt, wird das Pipe-Ereignis des beschreibbaren Streams ausgelöst.
  • unpipe

Diese beiden Ereignisse werden verwendet, um den beschreibbaren Stream darüber zu informieren, dass Daten bald eintreffen und dass sie bald unterbrochen werden. Sie werden unter normalen Umständen selten verwendet. Die Methode

writeable.write()

hat einen Bool-Rückgabewert

highWaterMark

, wenn die zu schreibenden Daten größer sind als der highWaterMark des beschreibbaren Streams, werden die Daten nicht sofort geschrieben. Zu diesem Zeitpunkt wird writeable.write() zurückgegeben. Wenn es verarbeitet werden kann, wird true zurückgegeben .write() hat „false“ zurückgegeben. Nach einer gewissen Zeit wurde der Datenrückstand verarbeitet und es wird ausgelöst, wenn neue Daten geschrieben werden können (die ursprüngliche Bedeutung von „drain“ ist Entwässerung und Erschöpfung, was recht anschaulich ist)

除了 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

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

Das obige ist der detaillierte Inhalt vonWas ist ein beschreibbarer Stream in Nodejs? Wie zu verwenden. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen