ReadableStream

Baseline 廣泛可用 *

此功能已成熟,並可在多種裝置和瀏覽器版本上使用。自 ⁨2019 年 1 月⁩起,它已在所有瀏覽器中可用。

* 此特性的某些部分可能存在不同級別的支援。

注意:此功能在 Web Workers 中可用。

ReadableStream 介面是 Streams API 的一部分,代表一個可讀的位元組資料流。 Fetch API 透過 body 屬性提供了一個 ReadableStream 的具體例項,該屬性是 Response 物件的一部分。

ReadableStream 是一個 可轉移物件

建構函式

ReadableStream()

從給定的處理程式建立並返回一個可讀流物件。

例項屬性

ReadableStream.locked 只讀

返回一個布林值,指示可讀流是否已被讀取器鎖定。

靜態方法

ReadableStream.from() 實驗性

從提供的可迭代物件或非同步可迭代物件(如陣列、集合、非同步生成器等)返回 ReadableStream

例項方法

ReadableStream.cancel()

返回一個 Promise,當流被取消時解析。呼叫此方法表示消費者對該流不再感興趣。提供的 reason 引數將傳遞給底層源,源可能會也可能不會使用它。

ReadableStream.getReader()

建立一個讀取器並將流鎖定到該讀取器。當流被鎖定後,在釋放此讀取器之前,不能獲取其他讀取器。

ReadableStream.pipeThrough()

提供了一種鏈式方式,將當前流透過轉換流或任何其他可寫/可讀對進行管道傳輸。

ReadableStream.pipeTo()

將當前 ReadableStream 管道傳輸到指定的 WritableStream,並返回一個 Promise。當管道傳輸成功完成時,該 Promise 會 fulfilled;如果遇到任何錯誤,則會 rejected。

ReadableStream.tee()

tee 方法 此可讀流進行分叉,返回一個包含兩個新 ReadableStream 例項的兩個元素的陣列。這兩個流接收相同的資料。

非同步迭代

ReadableStream 實現 非同步迭代協議。這使得可以使用 for await...of 語法非同步迭代流中的塊。

js
const stream = new ReadableStream(getSomeSource());

for await (const chunk of stream) {
  // Do something with each 'chunk'
}

非同步迭代器會消耗流,直到它沒有更多資料或終止。迴圈也可以由於 breakthrowreturn 語句而提前退出。

在迭代期間,流會被鎖定,以防止其他消費者獲取讀取器(嘗試迭代一個已被鎖定的流將丟擲 TypeError)。此鎖在迴圈退出時會被釋放。

預設情況下,退出迴圈也會取消流,使其無法再被使用。要在退出迴圈後繼續使用流,請將 { preventCancel: true } 傳遞給流的 values() 方法。

js
for await (const chunk of stream.values({ preventCancel: true })) {
  // Do something with 'chunk'
  break;
}
// Acquire a reader for the stream and continue reading ...

示例

Fetch 流

在以下示例中,建立了一個人工 Response 物件,以將從其他資源獲取的 HTML 片段流式傳輸到瀏覽器。

它演示了 ReadableStreamUint8Array 結合使用的用法。

js
fetch("https://www.example.org")
  .then((response) => response.body)
  .then((rb) => {
    const reader = rb.getReader();

    return new ReadableStream({
      start(controller) {
        // The following function handles each data chunk
        function push() {
          // "done" is a Boolean and value a "Uint8Array"
          reader.read().then(({ done, value }) => {
            // If there is no more data to read
            if (done) {
              console.log("done", done);
              controller.close();
              return;
            }
            // Get the data and send it to the browser via the controller
            controller.enqueue(value);
            // Check chunks by logging to the console
            console.log(done, value);
            push();
          });
        }

        push();
      },
    });
  })
  .then((stream) =>
    // Respond with our stream
    new Response(stream, { headers: { "Content-Type": "text/html" } }).text(),
  )
  .then((result) => {
    // Do things with result
    console.log(result);
  });

將迭代器或非同步迭代器轉換為流

from() 靜態方法可以將迭代器(如 ArrayMap)或 (非同步)迭代器 轉換為可讀流。

js
const myReadableStream = ReadableStream.from(iteratorOrAsyncIterator);

在不支援 from() 方法的瀏覽器中,您可以改為建立自己的 自定義可讀流 來達到相同的效果。

js
function iteratorToStream(iterator) {
  return new ReadableStream({
    async pull(controller) {
      const { value, done } = await iterator.next();

      if (value) {
        controller.enqueue(value);
      }
      if (done) {
        controller.close();
      }
    },
  });
}

警告:此示例假定返回值(在 donetrue 時為 value)如果存在,也應視為要入隊的塊。某些迭代器 API 可能將返回值用於不同目的。您可能需要根據您互動的 API 來調整程式碼。

使用 for await...of 對流進行非同步迭代

此示例演示瞭如何使用 for await...of 迴圈處理 fetch() 響應,以迭代到達的塊。

js
const response = await fetch("https://www.example.org");
let total = 0;

// Iterate response.body (a ReadableStream) asynchronously
for await (const chunk of response.body) {
  // Do something with each chunk
  // Here we just accumulate the size of the response.
  total += chunk.length;
}

// Do something with the total
console.log(total);

規範

規範
Streams
# rs-class

瀏覽器相容性

另見