fetch中处理流

573 阅读3分钟

项目中在做关于流的处理,后端会返回一个流的形式的数据,一直在想用什么方式请求比较好,后来发现用fetch来处理是最好的。

关于fetch我之前了解的不是很多,只知道fetch也是接口请求方式的一种,为了关于这个流,我就去官网学习了一下,发现好像东西挺多的。主要英文官网太难啃了,主要还是看了中文类的文档(www.w3cschool.cn/fetch_api/),等有时间了,英文的文档需要好好学习一下。

一:fetch请求

关于fetch中文官网是这样说的

二:使用fetch

关于fetch的使用中文官网是这样说的

在项目中使用fetch请求,其中属性在官网中都可以找到说明。

fetch(url,{ method:'post',headers:{
        'Content-Type': 'application/json'},
        credentials: 'include',
        body: JSON.stringify(params)}).then(response=>{})

三:处理fetch中的流

既然是处理流,用的就是递归函数来读取和处理流数据,然后对流进行解码并分割处理,切分完成后再继续读取下一段流数据。因为fetch方法是允许去跟踪下载进度的,使用 response.body 属性,与 response.text(),response.json() 和其他方法不同,response.body 给予了对进度读取的完全控制,我们可以随时计算下载了多少。当所有的流都处理完成后就需要退出递归函数,reader.read()使用后的结果是一个具有两个属性的对象,一个是done,一个是value,

  1. done :当所有的流读取完成时值为 true ,否则为 false
  2. value :字节的类型化数组 :Uint8Array

正常执行fetch后,不是调用response.json()而是获得了一个流读取器response.body.getReader()。

用递归函数来读取并处理读取到的流

// 创建文本解码器并获取可读流
const decoder = new TextDecoder();
const reader = response.body.getReader();
var content=''
// 递归函数来读取并处理流数据
const read = () => {
  reader.read().then(({ done, value }) => {
  // console.log('读取', done, value)
    if (done) return
  	
    // 解码并分割事件
    const text = decoder.decode(value);
    const events = text.split('\n');
    content +=text
    // 继续读取下一段流数据
         read();
       })
    };
    // 开始读取流数据
    read();

在递归中接受响应的数据流,当所有的响应的数据流加载完成后,也就是done的值为true的时候,说明所有的流都加载完成,可以进行下一步处理,退出递归或者处理其他的。

因为需求是要类似于那种文字输出有停顿感的样子,所以用fetch来处理,后端给的流会处理好输出的数据速度,只要在使用的时候注意递归的方式,处理好递归中的流数据,就可以啦

createdValue(){
      const params={
        prompt:prompt,
        contextId:contextId
      }
      fetch(url,{ method:'post',headers:{
        'Content-Type': 'application/json'},
        credentials: 'include',
        body: JSON.stringify(params)}).then(response=>{
        // 创建文本解码器并获取可读流
        const decoder = new TextDecoder();
        const reader = response.body.getReader();
        var content=''
            // 递归函数来读取并处理流数据
        const read = () => {
          reader.read().then(({ done, value }) => {
            // console.log('读取', done, value)
            if (done) return;
            // 解码并分割事件
            const text = decoder.decode(value);
            const events = text.split('\n');
            content+=text
            // 继续读取下一段流数据
            read();
          })
        };
        // 开始读取流数据
        read();
       
      }).catch(error => {
        console.error(error);
      });