Skip to main content

数据流式获取

使用 ChatGPT 时,因为计算过程需要比较长的时间,一般都不会等到全部计算完再一起展示结果,而是一个字一个字的算出来的。

我们通过 fetch 发起请求拿到响应结果 resp,这时候的时间点是响应头到达客户端的时间点

因此对于流式大数据,此时不能获取完整响应体的内容。

async function getResponse() {
// 此时 resp 拿到响应结果时,响应体还没有传输完成
const resp = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: '讲个困困和马老师打拳击的故事'
})
})
// 等待响应体传输完成(服务器返回纯文本)
const msg = await resp.text()
console.log(msg)
}

这样用户需要等待很长时间,用户体验很差。

那么如何做到数据流式读取?

async function getResponse() {
const resp = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: '讲个困困和马老师打拳击的故事'
})
})
// resp.body 是一个流, 通过 getReader 读取器部分部分地读
const reader = resp.body.getReader()
while (1) {
// 多次调用读取器的 read 方法,读取小块数据,返回一个 Promise
const { done, value } = await reader.read()
// 获取到的 value 是类型化数组,是那一小块数据的文本编码
console.log(value)
if (done) {
break
}
}
}

通过 TextDecoder 将文本编码解码成文字:

async function getResponse() {
const resp = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: '讲个困困和马老师打拳击的故事'
})
})

const reader = resp.body.getReader()
// 解码器
const textDecoder = new TextDecoder()
while (1) {
const { done, value } = await reader.read()
// 解码成文字
const str = textDecoder.decode(value)
console.log(str)
if (done) {
break
}
}
}