Heim  >  Artikel  >  Web-Frontend  >  Streams in Node.js verstehen

Streams in Node.js verstehen

青灯夜游
青灯夜游nach vorne
2020-11-19 17:48:582899Durchsuche

Streams in Node.js verstehen

Verwandte Empfehlungen: „nodejs-Tutorial

Für die meisten Studenten mit Back-End-Erfahrung ist das Stream-Objekt ein vernünftiges und häufiges Objekt, aber für Front-End-Studenten ist Stream nicht so selbstverständlich ist auf Github? Es gibt einen Artikel mit mehr als 9.000 Sternen, der vorstellt, was Stream ist – Stream-Handbuch (https://link.zhihu.com/?target=https%3A//github.com/substack/stream-handbook ). Um Stream besser zu verstehen, fassen wir es anhand dieses Artikels kurz zusammen.

Was ist Stream? Stream ist ein sehr verbreitetes und wichtiges Konzept in Unix-Systemen. In der Terminologie ist Stream eine Abstraktion von Eingabe- und Ausgabegeräten.

ls | grep *.js

Beim Schreiben von Skripten stoßen wir häufig auf Codes wie diesen. Verwenden Sie

|

, um zwei Befehle zu verbinden und das Ergebnis des vorherigen Befehls als Parameter des nächsten Befehls zu übergeben, sodass Daten wie Wasser sind durch eine Pipe fließen, und jeder Befehl ist wie ein Prozessor, der eine Verarbeitung der Daten durchführt, daher wird | als „Pipeline-Symbol bezeichnet. | 连接两条命令,把前一个命令的结果作为后一个命令的参数传入,这样数据像是水流在管道中传递,每个命令类似一个处理器,对数据做一些加工,因此 | 被称为 “管道符号”。

NodeJS 中 Stream 的几种类型

从程序角度而言流是有方向的数据,按照流动方向可以分为三种流

  • 设备流向程序:readable

  • 程序流向设备:writable

  • 双向:duplex、transform

NodeJS 关于流的操作被封装到了 Stream 模块,这个模块也被多个核心模块所引用。按照 Unix 的哲学:一切皆文件,在 NodeJS 中对文件的处理多数使用流来完成

  • 普通文件

  • 设备文件(stdin、stdout)

  • 网络文件(http、net)

有一个很容易忽略的知识点:在 NodeJS 中所有的 Stream 都是 EventEmitter 的实例。

小例子

我们写程序忽然需要读取某个配置文件 config.json,这时候简单分析一下

  • 数据:config.json 的内容
  • 方向:设备(物理磁盘文件) -> NodeJS 程序

我们应该使用 readable 流来做此事

const fs = require('fs');
const FILEPATH = '...';

const rs = fs.createReadStream(FILEPATH);

通过 fs 模块提供的 createReadStream() 方法我们轻松的创建了一个可读的流,这时候  config.json 的内容从设备流向程序。我们并没有直接使用 Stream 模块,因为 fs 内部已经引用了 Stream 模块,并做了封装。

有了数据后我们需要处理,比如需要写到某个路径 DEST ,这时候我们遍需要一个 writable 的流,让数据从程序流向设备。

const ws = fs.createWriteStream(DEST);

两种流都有了,也就是两个数据加工器,那么我们如何通过类似 Unix 的管道符号 | 来链接流呢?在 NodeJS 中管道符号就是 pipe()

Mehrere Arten von Streams in NodeJS

Aus Programmsicht handelt es sich bei Stream um

Richtungsdaten, die in drei Arten unterteilt werden können Flüsse

    Gerätefluss zum Programm: lesbar

    Programmfluss zum Gerät: beschreibbar

    bidirektional: Duplex, Transformation

    • NodeJS About Stream-Vorgänge sind im Stream-Modul gekapselt, auf das auch mehrere Kernmodule verweisen. Gemäß der Unix-Philosophie: Alles ist eine Datei, die meiste Dateiverarbeitung in NodeJS erfolgt über Streams
      Gewöhnliche Dateien

      Gerätedateien (stdin, stdout )

      Netzwerkdateien (http, net)

      🎜🎜Es gibt einen Wissenspunkt, der leicht übersehen wird: Alle Streams in NodeJS sind Instanzen von EventEmitter. 🎜

      Kleines Beispiel🎜🎜Wenn wir ein Programm schreiben, müssen wir plötzlich eine bestimmte Konfigurationsdatei 🎜config.json lesen. Zu diesem Zeitpunkt werden wir kurz den Inhalt von 🎜 analysieren 🎜🎜Daten: config.json🎜 🎜Richtung: Gerät (physische Festplattendatei) -> NodeJS-Programm🎜🎜🎜Wir sollten dafür lesbare Streams verwenden🎜
      const fs = require('fs');
      const FILEPATH = '...';
      
      const rs = fs.createReadStream(FILEPATH);
      const ws = fs.createWriteStream(DEST);
      
      rs.pipe(ws);
      🎜Wir können es einfach über createReadStream()-Methode, die vom fs-Modul bereitgestellt wird. Ein lesbarer Stream, wenn der Inhalt von 🎜config.json vom Gerät zum Programm fließt. Wir haben das Stream-Modul nicht direkt verwendet, da fs das Stream-Modul bereits intern referenziert und gekapselt hat. 🎜🎜Nachdem wir die Daten haben, müssen wir sie verarbeiten. Zu diesem Zeitpunkt benötigen wir einen beschreibbaren Stream, damit die Daten vom Programm zum Gerät fließen können. 🎜<pre class="brush:php;toolbar:false">const fs = require('fs'); const rs = fs.createReadStream('./package.json'); const ws = fs.createWriteStream('./package-lower.json'); rs.pipe(lower).pipe(ws);</pre>🎜Es gibt zwei Streams, also zwei Datenprozessoren. Wie verknüpfen wir die Streams also über das Unix-ähnliche Pipe-Symbol <code>|? Das Pipe-Symbol in NodeJS ist die Methode pipe(). 🎜
      rs.pipe(lower).pipe(acsii).pipe(ws);
      🎜Auf diese Weise verwenden wir den Stream, um eine einfache Dateikopierfunktion zu implementieren. Das Implementierungsprinzip der Methode „pipe()“ wird später erwähnt, aber es gibt eine Sache, die es zu beachten gilt: Die Daten müssen vom Upstream nach weitergeleitet werden der Downstream, also von einer lesbaren Stream-Pipe zu einem beschreibbaren Stream. 🎜🎜Verarbeiten Sie die Daten🎜🎜Die oben genannten lesbaren und beschreibbaren Streams nennen wir Prozessoren, was eigentlich nicht angemessen ist, da wir nichts verarbeiten, sondern nur die Daten lesen und dann speichern. 🎜🎜Ändern Sie bei Bedarf alle Buchstaben in der lokalen Datei 🎜package.json🎜 in Kleinbuchstaben und speichern Sie sie in der Datei package-lower.json im selben Verzeichnis. 🎜🎜Zu diesem Zeitpunkt müssen wir einen Zwei-Wege-Stream verwenden, der auf die Konvertierung von Zeichen in Kleinbuchstaben spezialisiert ist. 🎜
      const http = require('http');
      const fs = require('fs');
      
      http.createServer((req, res) => {
         fs.readFile(moviePath, (err, data) => {
            res.end(data);
         });
      }).listen(8080);
      🎜Zu diesem Zeitpunkt können wir sehen, warum das so ist aufgerufene Pipe()-Verbindung Der Stream ist ein Prozessor, der von einem lesbaren Stream zu einem beschreibbaren Stream weitergeleitet werden muss: 🎜🎜🎜lower: niedriger ist stromabwärts, also muss niedriger ein sein beschreibbarer Stream 🎜🎜lower -> Wir werden die spezifische Verwendung von Duplex oder Transformation später erwähnen. 🎜🎜Natürlich, wenn wir einige zusätzliche Verarbeitungsaktionen haben, wie zum Beispiel Buchstaben, die in ASCII-Codes umgewandelt werden müssen, vorausgesetzt, es gibt einen ASCII-Stream, dann kann unser Code sein 🎜
      const http = require('http');
      
      const fs = require('fs');
      
      http.createServer((req, res) => {
      
         fs.createReadStream(moviePath).pipe(res);
      
      }).listen(8080);
      🎜Ähnlich muss auch ASCII ein bidirektionaler Stream sein. Die Logik dieser Verarbeitung ist sehr klar. Welche Vorteile hat die Verwendung von Streams neben klarem Code? 🎜🎜Warum Sie Stream verwenden sollten🎜🎜Es gibt ein Szenario, in dem ein Benutzer ein Video online ansehen muss. Angenommen, wir geben den Filminhalt über eine HTTP-Anfrage an den Benutzer zurück, dann könnte der Code so geschrieben sein🎜
      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);

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

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

      Das obige ist der detaillierte Inhalt vonStreams in Node.js verstehen. 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