Die Streams API fügt dem Web-Framework eine sehr nützliche Sammlung von Werkzeugen hinzu und bietet Objekte, die es JavaScript ermöglichen, programmgesteuert auf Datenströme zuzugreifen, die über das Netzwerk empfangen werden, und diese nach Belieben des Entwicklers zu verarbeiten. Einige der mit Streams verbundenen Konzepte und Begriffe könnten Ihnen neu sein â dieser Artikel erklärt alles, was Sie wissen müssen.
Lesbare StreamsEin lesbarer Stream ist eine Datenquelle, die in JavaScript durch ein ReadableStream
-Objekt dargestellt wird und von einer zugrunde liegenden Quelle stammt â dies ist eine Ressource irgendwo im Netzwerk oder anderswo in Ihrer Domain, von der Sie Daten beziehen möchten.
Es gibt zwei Arten von zugrunde liegenden Quellen:
fetch()
-Anfrage.Die Daten werden sequenziell in kleinen Stücken, sogenannten Chunks, gelesen. Ein Chunk kann ein einzelnes Byte sein, oder etwas GröÃeres wie ein typisiertes Array einer bestimmten GröÃe. Ein einzelner Stream kann Chunks unterschiedlicher GröÃen und Typen enthalten.
Die in einem Stream platzierten Chunks werden als eingereiht bezeichnet â das bedeutet, dass sie in einer Warteschlange darauf warten, gelesen zu werden. Eine interne Warteschlange hält den Ãberblick über die Chunks, die noch nicht gelesen wurden (siehe den Abschnitt zu internen Warteschlangen und Warteschlangenstrategien unten).
Leser, Verbraucher und ControllerDie Chunks im Inneren des Streams werden von einem Leser gelesen â dieser verarbeitet die Daten Stück für Stück und ermöglicht Ihnen, jede gewünschte Art von Operation darauf auszuführen. Der Leser plus der zusammenhängende Verarbeitungs-Code wird als Verbraucher bezeichnet.
Es gibt auch eine Konstruktion, die Sie nutzen werden, genannt Controller â jeder Leser hat einen zugehörigen Controller, der es Ihnen ermöglicht, den Stream zu kontrollieren (zum Beispiel ihn zu schlieÃen, wenn gewünscht).
SperrenNur ein Leser kann einen Stream gleichzeitig lesen; wenn ein Leser erstellt wird und beginnt, einen Stream zu lesen (ein aktiver Leser), sagen wir, dass er daran gesperrt ist. Wenn Sie möchten, dass ein anderer Leser Ihren Stream liest, müssen Sie normalerweise den ersten Leser abbrechen, bevor Sie etwas anderes tun (obwohl Sie Streams auch aufteilen können, siehe den Abschnitt Teeing unten).
Lesbare Streams und Byte StreamsBeachten Sie, dass es zwei verschiedene Arten von lesbaren Streams gibt. Neben dem konventionellen lesbaren Stream gibt es einen Typ namens Byte Stream â dies ist eine erweiterte Version eines konventionellen Streams zum Lesen zugrundeliegender Byte-Quellen. Im Vergleich zum konventionellen lesbaren Stream dürfen Byte Streams von BYOB-Lesern gelesen werden (BYOB, "bring your own buffer"). Dieser Reader-Typ ermöglicht es, Streams direkt in einen vom Entwickler bereitgestellten Puffer zu lesen, was das erforderliche Kopieren minimiert. Welchen zugrunde liegenden Stream (und im weiteren Sinne, welche Leser und Controller) Ihr Code verwenden wird, hängt davon ab, wie der Stream ursprünglich erstellt wurde (siehe die Seite zum ReadableStream()
-Konstruktor).
Sie können gebrauchsfertige lesbare Streams über Mechanismen wie ein Response.body
einer Fetch-Anfrage nutzen oder Ihre eigenen Streams mit dem ReadableStream()
-Konstruktor erstellen.
Auch wenn nur ein einzelner Leser einen Stream gleichzeitig lesen kann, ist es möglich, einen Stream in zwei identische Kopien zu teilen, die dann von zwei separaten Lesern gelesen werden können. Dies wird als Teeing bezeichnet.
In JavaScript wird dies durch die Methode ReadableStream.tee()
erreicht â sie gibt ein Array aus, das zwei identische Kopien des ursprünglichen lesbaren Streams enthält, die dann unabhängig voneinander von zwei separaten Lesern gelesen werden können.
Sie könnten dies zum Beispiel in einem ServiceWorker tun, wenn Sie eine Antwort vom Server abrufen und an den Browser streamen möchten, aber auch an den ServiceWorker-Cache streamen wollen. Da ein Antwortkörper nicht mehr als einmal konsumiert werden kann und ein Stream nicht mehr als von einem Leser gleichzeitig gelesen werden kann, benötigen Sie dazu zwei Kopien.
Schreibbare StreamsEin schreibbarer Stream ist ein Ziel, in das Sie Daten schreiben können, dargestellt in JavaScript durch ein WritableStream
-Objekt. Dies dient als Abstraktion über einem zugrunde liegenden Senke â einer I/O-Senke auf niedrigerer Ebene, in die Rohdaten geschrieben werden.
Die Daten werden über einen Schreiber an den Stream geschrieben, und zwar ein Chunk nach dem anderen. Ein Chunk kann viele Formen annehmen, genau wie die Chunks in einem Leser. Sie können beliebigen Code verwenden, um die zum Schreiben bereitstehenden Chunks zu erzeugen; der Schreiber plus der zugehörige Code wird als Produzent bezeichnet.
Wenn ein Schreiber erstellt wird und beginnt, in einen Stream zu schreiben (ein aktiver Schreiber), wird gesagt, dass er daran gesperrt ist. Nur ein Schreiber kann gleichzeitig in einen schreibbaren Stream schreiben. Wenn Sie möchten, dass ein anderer Schreiber in Ihren Stream zu schreiben beginnt, müssen Sie diesen normalerweise abbrechen, bevor Sie dann einen anderen Schreiber daran anhängen.
Eine interne Warteschlange verfolgt die Chunks, die in den Stream geschrieben, aber noch nicht von der zugrunde liegenden Senke verarbeitet wurden.
Es gibt auch eine Konstruktion, die Sie nutzen werden, genannt Controller â jeder Schreiber hat einen zugehörigen Controller, der es Ihnen ermöglicht, den Stream zu kontrollieren (zum Beispiel ihn abzubrechen, wenn gewünscht).
Sie können schreibbare Streams mit dem WritableStream()
-Konstruktor verwenden. Diese haben derzeit eine sehr begrenzte Verfügbarkeit in Browsern.
Die Streams API ermöglicht es, Streams durch eine Struktur, die als Pipe-Kette bezeichnet wird, ineinander zu leiten. Es gibt zwei Methoden, die dies erleichtern:
ReadableStream.pipeThrough()
â leitet den Stream durch einen Transform-Stream, wobei möglicherweise das Datenformat verändert wird. Dies könnte verwendet werden, um Video-Frames zu kodieren oder zu dekodieren, Daten zu komprimieren oder zu dekomprimieren oder Daten anderweitig von einer Form in eine andere umzuwandeln.
Ein Transform-Stream besteht aus einem Paar von Streams: einem lesbaren Stream, aus dem Daten gelesen werden, und einem schreibbaren Stream, in den sie geschrieben werden, zusammen mit geeigneten Mechanismen, um sicherzustellen, dass neue Daten verfügbar gemacht werden, sobald die Daten geschrieben wurden.
TransformStream
ist eine konkrete Implementierung eines Transform-Streams, aber jedes Objekt, das dieselben lesbaren Stream- und schreibbaren Stream-Eigenschaften besitzt, kann an pipeThrough()
übergeben werden.
ReadableStream.pipeTo()
â leitet an einen schreibbaren Stream, der als Endpunkt der Pipe-Kette fungiert.
Der Beginn der Pipe-Kette wird als ursprüngliche Quelle bezeichnet, und das Ende wird als endgültige Senke bezeichnet.
RückstauEin wichtiges Konzept bei Streams ist der Rückstau â dies ist der Prozess, durch den ein einzelner Stream oder eine Pipe-Kette die Geschwindigkeit des Lesens/Schreibens reguliert. Wenn ein Stream später in der Kette noch beschäftigt ist und noch nicht bereit ist, weitere Chunks zu akzeptieren, sendet er ein Signal rückwärts durch die Kette, um den früheren Transform-Streams (oder der ursprünglichen Quelle) mitzuteilen, die Lieferung zu verlangsamen, um zu vermeiden, dass irgendwo ein Engpass entsteht.
Um Rückstau in einem ReadableStream
zu verwenden, können wir den Controller nach der vom Verbraucher gewünschten Chunk-GröÃe fragen, indem wir die Eigenschaft ReadableStreamDefaultController.desiredSize
am Controller abfragen. Wenn sie zu klein ist, kann unser ReadableStream
seiner zugrunde liegenden Quelle sagen, dass sie aufhören soll, Daten zu senden, und wir üben Rückstau entlang der Stream-Kette aus.
Wenn der Verbraucher später erneut Daten empfangen möchte, können wir die Pull-Methode in der Stream-Erstellung verwenden, um unserer zugrunde liegenden Quelle mitzuteilen, unseren Stream mit Daten zu versorgen.
Interne Warteschlangen und WartestrategienWie bereits erwähnt, werden die Chunks in einem Stream, die noch nicht verarbeitet und abgeschlossen wurden, von einer internen Warteschlange verfolgt.
Interne Warteschlangen verwenden eine Warteschlangenstrategie, die bestimmt, wie Rückstau basierend auf dem Status der internen Warteschlange signalisiert wird.
Im Allgemeinen vergleicht die Strategie die GröÃe der Chunks in der Warteschlange mit einem Wert, der als High Water Mark bezeichnet wird, der die gröÃte gesamte Chunk-GröÃe ist, die die Warteschlange verwalten möchte.
Die durchgeführte Berechnung ist
High Water Mark - GesamtgröÃe der Chunks in der Warteschlange = gewünschte GröÃe
Die gewünschte GröÃe ist die Anzahl der Chunks, die der Stream noch akzeptieren kann, um den Stream flieÃen zu lassen, aber unter der High Water Mark in der GröÃe zu bleiben. Die Chunk-Erzeugung wird entsprechend verlangsamt/beschleunigt, um den Stream so schnell wie möglich flieÃen zu lassen, während die gewünschte GröÃe über null bleibt. Wenn der Wert auf null (oder darunter) fällt, bedeutet dies, dass Chunks schneller erzeugt werden als der Stream bewältigen kann, was zu Problemen führen kann.
Als Beispiel nehmen wir eine Chunk-GröÃe von 1 und eine High Water Mark von 3. Dies bedeutet, dass bis zu 3 Chunks eingereiht werden können, bevor die High Water Mark erreicht wird und Rückstau angewendet wird.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4