• 0

  • 479

fetch API新特性: Stremaing Request

6天前

TL;DR

Chrome 85为fetch API加入了一个实验中的新特性:流式请求(Streaming Request),现在可以将fetch请求体设置为一个可读流对象,在请求体尚未构造完全的时候就可以先发起请求,并在后续往可读流填入更多数据


const stream = new ReadableStream();

fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'text/plain' },
  body: stream,
});

复制代码

从Streaming说起

在网络环境较差的条件下,有时你会看到浏览器加载例如图片等资源,会边下载边一点一点慢慢地把图片渲染出来,而不是等整张图片下载完了以后才进行图片渲染工作,这其实就是流机制的一种应用:你可以在获取完整的数据以前,先对已经抵达的部分数据块(chunk)进行处理,从而提高硬件使用效率,减少用户白屏等待时间。使用流机制与不进行流机制进行图片下载处理渲染的流程区别如下图所示

流机制在以前是没有直接暴露给JavaScript脚本使用的,直到Streaming Sepc出来以后,开发者才可以通过规范提供的Streaming API对流进行操作,再到后来流操作被集成进fetch API,我们已经可以以流的方式处理响应数据

Streaming Response

流式响应已经存在相当长的一段时间,并且已经属于一个stable feature。通过流式响应,我们可以操作已经到达的响应数据块,而不必等待完整的响应体到达。

const response = await fetch(url);
const reader = response.body.getReader();

while (true) {
  const { value, done } = await reader.read(); // value是一个UInt8Array,数组长度取决于网络质量
  if (done) break;
  console.log('Received', value);
}

console.log('Response fully received');
复制代码

Google Devloper给出了一个十分常见的用例:

you can start acting on the data as it arrives. For instance, if you're receiving a list of 100 'results', you can display the first result as soon as you receive it, rather than waiting for all 100.


无论如何,Streaming Response已经存在很久了,可以放心去使用它,真正新奇的是Streaming Request的登场

Streaming Request

如同文章开头所说的那样,现在可以将fetch API的请求体设置为一个可读流(ReadableStream),你可以在获取完整的请求体之前就先发出请求,并在后续对请求体不断进行填充,这在请求体是动态生成的场景下十分有用,比如说要上传到服务器的某个文件,它的内容是随时间动态生成的,而我们想复用同一个TCP连接同一个HTTP请求进行传输从而降低开销,那么使用Streaming Request是最好的选择。创建一个可读流readable,并且将其作为fetch的请求体,然后创建一个可写流writable,将writable通过管道连接到readable,不断往writable写入数据,数据会经过管道流入readable,并且发送到服务端

const {readable, writable} = new TransformStream();

fetch('/upload', {
    method: 'POST',
    headers: { 'Content-Type': 'text/plain' },
    body: readable
})

// 往writable写入动态生成的文件内容
复制代码

除此之外,Google Developer还给出了以下几个有趣的Use Case

  • Warm up the server. In other words, you could start the request once the user focuses a text input field, and get all of the headers out of the way, then wait until the user presses 'send' before sending the data they entered.
  • Recreate web sockets over HTTP.

对于使用fetch API去hack出一个websocket的例子,他们也给出了一个对应的demo,点击此处查看

使用fetch构建websocket需要服务端配合,不过我没有找到官方demo的服务端源代码,所以自己尝试实现了一下整个demo,其中客户端代码大部分参考demo

自己尝试造的轮子

每次点击fill in request body都会向服务端发送内容为"chunk"的字符串数据,并且服务端会将客户端发送过来的所有数据做一个round trip,返回给客户端自己,直到点击end request销毁可读流

总结

本文仅仅是抛砖引玉,对fetch API的Streaming Request新特性以及已经存在许久的Streaming Response特性做一个简要的概述,如果对Streaming感兴趣的同学可以进一步阅读以下资源,本文有大量内容也是引用于以下文章/视频

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

程序员

479

相关文章推荐

未登录头像

暂无评论