ReadableStreamDefaultReader: read() 方法

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流浏览器均已支持。

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

ReadableStreamDefaultReader 接口的 read() 方法返回一个 Promise,该 Promise 提供对流内部队列中下一个数据块的访问。

语法

js
read()

参数

无。

返回值

一个 Promise,它会根据流的状态来 fulfilled/rejected。各种可能性如下:

  • 如果数据块可用,Promise 将会 fulfilled,并带有 `{ value: theChunk, done: false }` 形式的对象。
  • 如果流关闭,Promise 将会 fulfilled,并带有 `{ value: undefined, done: true }` 形式的对象。
  • 如果流发生错误,Promise 将会 rejected,并带有相关的错误。

异常

TypeError

源对象不是 ReadableStreamDefaultReader,流没有拥有者,或者调用了 ReadableStreamDefaultReader.releaseLock()(当有待处理的 read 请求时)。

示例

示例 1 - 简单示例

此示例展示了基本的 API 用法,但并未尝试处理例如流数据块不以换行符结束等复杂情况。

在此示例中,stream 是一个先前创建的自定义 ReadableStream。它使用通过 getReader() 创建的 ReadableStreamDefaultReader 进行读取。(有关完整代码,请参阅我们的 简单随机流示例)。每个数据块按顺序读取并作为 UTF-8 字节数组输出到 UI,直到流读取完毕,此时我们从递归函数返回,并将整个流打印到 UI 的另一部分。

js
function fetchStream() {
  const reader = stream.getReader();
  let charsReceived = 0;

  // read() returns a promise that fulfills
  // when a value has been received
  reader.read().then(function processText({ done, value }) {
    // Result objects contain two properties:
    // done  - true if the stream has already given you all its data.
    // value - some data. Always undefined when done is true.
    if (done) {
      console.log("Stream complete");
      para.textContent = result;
      return;
    }

    // value for fetch streams is a Uint8Array
    charsReceived += value.length;
    const chunk = value;
    let listItem = document.createElement("li");
    listItem.textContent = `Received ${charsReceived} characters so far. Current chunk = ${chunk}`;
    list2.appendChild(listItem);

    result += chunk;

    // Read some more, and call this function again
    return reader.read().then(processText);
  });
}

示例 2 - 按行处理文本

此示例展示了如何获取文本文件并将其作为文本行流进行处理。它处理了数据块不以换行符结束,以及从 Uint8Array 转换为字符串的情况。

js
async function* makeTextFileLineIterator(fileURL) {
  const utf8Decoder = new TextDecoder("utf-8");
  let response = await fetch(fileURL);
  let reader = response.body.getReader();
  let { value: chunk, done: readerDone } = await reader.read();
  chunk = chunk ? utf8Decoder.decode(chunk, { stream: true }) : "";

  let re = /\r?\n/g;
  let startIndex = 0;

  for (;;) {
    let result = re.exec(chunk);
    if (!result) {
      if (readerDone) {
        break;
      }
      let remainder = chunk.substring(startIndex);
      ({ value: chunk, done: readerDone } = await reader.read());
      chunk =
        remainder + (chunk ? utf8Decoder.decode(chunk, { stream: true }) : "");
      startIndex = re.lastIndex = 0;
      continue;
    }
    yield chunk.substring(startIndex, result.index);
    startIndex = re.lastIndex;
  }
  if (startIndex < chunk.length) {
    // last line didn't end in a newline char
    yield chunk.substring(startIndex);
  }
}

for await (let line of makeTextFileLineIterator(urlOfFile)) {
  processLine(line);
}

规范

规范
Streams
# 默认读取器的参考①

浏览器兼容性

另见