WritableStream - 提供了用于将流数据写入目标的标准抽象

这是一个实验中的功能
此功能某些浏览器尚在开发中,请参考浏览器兼容性表格以得到在不同浏览器中适合使用的前缀。由于该功能对应的标准文档可能被重新修订,所以在未来版本的浏览器中该功能的语法和行为可能随之改变。

WritableStreamStreams API 的接口,提供了用于将流数据写入目标(称为接收器)的标准抽象。该对象带有内置的反压和排队。

构造函数

WritableStream()

创建一个新的 WritableStream 对象。

属性

WritableStream.locked 只读

一个布尔值,指示 WritableStream 是否已锁定到写入器。

方法

WritableStream.abort()

中止该流,表明生产者无法再成功写入该流,并且应立即将其移至错误状态,并丢弃所有排队的写操作。

WritableStream.close()

关闭流。

WritableStream.getWriter()

返回一个新的 WritableStreamDefaultWriter 实例,并将流锁定到该实例。流被锁定后,在释放该写入器之前,无法再获取其他写入器。

实例

以下实例说明了此接口的一些功能。它显示了使用自定义接收器和 API 提供的排队策略创建 WritableStream 的过程。然后,它调用一个名为 sendMessage() 的函数,传递新创建的流和一个字符串。在此函数内,它调用流的 getWriter() 方法,该方法返回一个 WritableStreamDefaultWriter 的实例。接着调用 forEach() 将字符串的每个块写入流中。最后,write()close() 返回处理块和流为成功或失败的承诺。

const list = document.querySelector('ul');

function sendMessage(message, writableStream) {
  // defaultWriter 的类型为 WritableStreamDefaultWriter
  const defaultWriter = writableStream.getWriter();
  const encoder = new TextEncoder();
  const encoded = encoder.encode(message, { stream: true });
  encoded.forEach((chunk) => {
    defaultWriter.ready
      .then(() => {
        return defaultWriter.write(chunk);
      })
      .then(() => {
        console.log("块写入接收器。");
      })
      .catch((err) => {
        console.log("块错误:", err);
      });
  });
  // 在关闭写入器之前,再次调用就绪以确保所有块均已写入。
  defaultWriter.ready
    .then(() => {
      defaultWriter.close();
    })
    .then(() => {
      console.log("所有的块已写入。");
    })
    .catch((err) => {
      console.log("流错误:", err);
    });
}

const decoder = new TextDecoder("utf-8");
const queuingStrategy = new CountQueuingStrategy({ highWaterMark: 1 });
let result = "";
const writableStream = new WritableStream({
  // 实现接收器
  write(chunk) {
    return new Promise((resolve, reject) => {
      var buffer = new ArrayBuffer(2);
      var view = new Uint16Array(buffer);
      view[0] = chunk;
      var decoded = decoder.decode(view, { stream: true });
      var listItem = document.createElement('li');
      listItem.textContent = "块解码:" + decoded;
      list.appendChild(listItem);
      result += decoded;
      resolve();
    });
  },
  close() {
    var listItem = document.createElement('li');
    listItem.textContent = "[收到消息] " + result;
    list.appendChild(listItem);
  },
  abort(err) {
    console.log("接收器错误:", err);
  }
}, queuingStrategy);

sendMessage("Hello, world.", writableStream);

您可以在我们的简单写入器实例中找到完整的代码。

反压

由于 API 中对反压的支持方式,它在代码中的实现可能不太直观。要了解反压力是如何实现的,请看以下三点:

  • 在创建计数策略时设置的 highWaterMark 属性(第 35 行)设置了 WritableStream 实例将在单个 write() 操作中处理的最大数据量。在此实例中,它是指可以发送到 defaultWriter.write()(第 11 行)的最大数据量。
  • defaultWriter.ready 属性返回一个承诺,该承诺将在接收器(WritableStream 构造函数的第一个属性)完成写入数据后解析。数据源可以写入更多数据(第 9 行)或调用 close()(第 24 行)。太早调用 close() 可能会阻止数据写入。这就是为什么该实例两次调用 defaultWriter.ready(第 9 和 22 行)的原因。
  • 接收器的 write() 方法(第 40 行)返回的 Promise 告诉 WritableStream 及其写入器何时解析 defaultWriter.ready

规范

规范 状态 备注
Streams
WritableStream 的定义
现行的标准 初始定义。

桌面浏览器兼容性

特性ChromeEdgeFirefoxInternet ExplorerOperaSafari
基础支持5916 不支持 不支持47 未知
WritableStream() 构造函数5916 不支持 不支持47 未知
abort5916 不支持 不支持47 未知
getWriter5916 不支持 不支持47 未知
locked5916 不支持 不支持47 未知

移动浏览器兼容性

特性AndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
基础支持5959 未知 不支持 未知44 未知
WritableStream() 构造函数5959 未知 不支持 未知44 未知
abort5959 未知 不支持 未知44 未知
getWriter5959 未知 不支持 未知44 未知
locked5959 未知 不支持 未知44 未知

相关链接