Streams 流處理

巴伐利亚药水哥發表於2024-08-14

〇、相關 Blogs

https://juejin.cn/post/6960629859827580965?searchId=202408140740572BA1324EA3445548BFDB

一、概述

1、概覽

以前,如果要處理某種資源(影片或文字檔案等),必須下載整個檔案,等待將其反序列化為合適的格式然後進行處理。隨著 JavaScript 可以使用流,這一切都發生了變化。現在,原始資料一旦可用,就可以使用 JavaScript 進行逐步處理,而不需要生成 buffer、string 或 blob

應用:

  • 影片特效:

    用管道(pipe)把一個可讀的影片流連線到一個可以新增實時特效的轉換流

  • 資料解壓/加壓縮

    用管道把一個檔案流連線到一個可以有選擇地(解)壓縮的轉換流

  • 圖片解碼:

    用管道把一個HTTP響應流連線到一個可以將位元組解碼為點陣圖資料的轉換流,然後在連線到一個可以將點陣圖轉換為PNG轉換流。如果是安裝在service worker的“fetch”中,這允許你透明地填充新的影像格式,如AVIF

2、一些名詞

  • Chunks

    Chunks 是寫入流或從流中讀取的單個資料。它可以是任何型別;流甚至可以包含很多不同型別的Chunk。大多數情況下,對一個流,chunk不是最原子的資料單元。例如,位元組流可能包含由16 KiBUint8Array單元組成的塊,而不是單個位元組。

  • 可讀流

    可讀流表示一個可以從中讀取的資料來源。換句話說,資料來自可讀流。具體地說,可讀流是ReadableStream類的例項。

  • 轉換流

    轉換流由一對流組成:可寫流(稱為其可寫端)和可讀流(稱為其可讀端)。一個真實的比喻是,一個即時從一種語言翻譯到另一種語言的同聲傳譯員。對於轉換流來說就是,向可寫側寫入導致新資料可用於從可讀側讀取。具體地說,任何具有可寫屬性和可讀屬性的物件都可以用作轉換流。然而,標準的TransformStream類使得建立這樣一物件變得更容易。

  • 管道鏈(Pipe chains)

    流主要透過管道相互連線來使用。可讀流可以使用其pipeTo()方法直接透過管道傳輸到可寫流,也可以使用可讀流的pipeThrough()方法透過一個或多個轉換流進行管道傳輸。以這種方式連線在一起的一組流稱為管道鏈。

  • 背壓(Backpressure)

    一旦一個管道鏈被構建,它將傳播關於Chunks應該以多快的速度流過的訊號。如果鏈中的任何一步還不能接收塊,它就會透過管道鏈向後傳播一個訊號,直到最終原始源被告知停止這麼快地生成chunks。 這種normalizing flow的過程稱為背壓。

  • Teeing

    可讀流可以使用tee()方法進行tee操作(以大寫“T”的形狀命名,一個入口兩個出口)。這將鎖定流,使其不再直接可用;但是,它將建立兩個新流,稱為分支,可以獨立使用。Teeing 也很重要,因為流不能倒帶或重新啟動,稍後將詳細介紹。

https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a1ef3c5c7a8a403baa7c453419dd7937~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp

可讀流的機制 #
一個可讀流是一個資料來源,在JavaScript中由一個從底層源流出的ReadableStream物件表示。ReadableStream建構函式從給定的handlers中建立並返回一個可讀的流物件。有兩種型別的底層源:

推送(push)源當你訪問它是,會不斷的向你推送資料,你可以開始、暫停或取消對流的訪問。示例包括實時影片流、server-sent events或WebSockets。
拉取(pull)源 要求你在連線到它們時顯式地請求資料。例子包括透過fetch()或XMLHttpRequest呼叫的HTTP操作。

流資料以稱為chunk的小塊順序讀取。放置在流中的塊稱為進入佇列。這意味著它們正在佇列中等待被讀取。內部佇列會跟蹤尚未讀取的資料塊。
佇列策略是一個能流內部佇列的狀態,決定流應該如何發出Backpressure訊號的物件。排隊策略為每個chunk分配一個大小,並將佇列中所有chunk的總大小與一個指定的數字(稱為高水位標記high water mark)進行比較。
流中的塊由reader讀取。這個reader一次檢索一個chunk,允許你對資料進行各種型別的操作。reader加上與之相伴的處理邏輯即被稱為消費者(consumer)。
還有一個構件叫做控制器(controller)。每個可讀流都有一個關聯的控制器,顧名思義,它允許你控制流。
一次只能有一個reader讀取流;當一個reader被建立並開始讀取一個流(也就是說,成為一個活動的reader)時,它就被鎖定在這個流上。如果你想讓另一個reader接管你的流,你通常需要先釋放第一個reader(儘管你可以tee流)。
建立一個可讀流 #
你可以透過呼叫 ReadableStream()建構函式建立一個可讀流。 這個建構函式有一個可選引數 underlyingSource, 它表示一個流例項將如何表現的方法和屬性。
The underlyingSource #
可以使用以下的可選方法,由開發人員自定義:

start(controller): 在物件被構造的時立刻被呼叫。該方法可以訪問流的源,並執行設定流功能所需的任何其他操作。如果這個過程是非同步完成的,該方法可以返回一個promise來表示成功或失敗. controller 引數是一個ReadableStreamDefaultController.
pull(controller): 可以用於在獲取chunks時控制流。只要流的內部chunks佇列沒有滿,它就會被反覆呼叫,直到佇列達到最高水位。如果呼叫pull()的結果是一個promise,那麼pull()將不會被再次呼叫,直到該promise fulfills。如果promise被reject,流就會出錯。
cancel(reason): 當流的消費者取消流時被呼叫.

相關文章