Fetch API 的工作机制及流式读取的时机

Fetch API 能实现流式读取数据,关键在于理解其工作机制以及流式读取的时机。

具体流程

  1. 发起请求:

    const response = await fetch('http://localhost:11434/api/generate', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            model: 'llama2',
            prompt: 'Tell me a story about a dragon.',
            stream: true,
        }),
    });
    
    • 此时,浏览器已经发送了请求,并等待服务器的响应。
    • response 是一个 Response 对象,但响应体数据还没有被读取。
  2. 获取可读流:

    const reader = response.body.getReader();
    
    • 这里只是获取了一个可读流的读取器(ReadableStreamDefaultReader),并没有开始读取数据。
  3. 逐步读取数据:

    while (true) {
        const { done, value } = await reader.read();
        if (done) break; // 如果流结束,退出循环
    
        // 处理数据块
        const chunk = new TextDecoder().decode(value);
        const data = JSON.parse(chunk);
        console.log(data.response);
    }
    
    • 数据是在 reader.read() 时逐步读取的。
    • 每次调用 reader.read() 会从服务器获取一个数据块,直到流结束(donetrue)。

response.body.getReader() 的执行时机

  1. await fetch 的机制:
    • 当你调用 await fetch(...) 时,浏览器会发起网络请求,并等待服务器的响应。
    • await fetch 的返回值是一个 Response 对象,但这个 Response 对象并不包含完整的响应体数据,而是一个表示 HTTP 响应的抽象对象。
    • 此时,响应体(response.body)是一个 可读流(ReadableStream),数据还没有被完全读取。
  2. response.body.getReader() 的作用:
    • response.body.getReader() 是用来从可读流中逐步读取数据的。
    • 调用 getReader() 并不会立即读取数据,而是返回一个 ReadableStreamDefaultReader 对象,用于后续逐步读取数据块。
  3. 数据读取的时机:
    • 数据是在调用 reader.read() 时逐步读取的,而不是在 await fetchgetReader() 时读取。
    • 每次调用 reader.read() 会返回一个 Promise,解析为一个包含数据块的对象({ done, value })。

关键点总结

  1. await fetch 的作用:
    • 发起请求并等待响应头返回。
    • 返回的 Response 对象包含响应头信息和一个可读流(response.body),但响应体数据还没有被读取。
  2. response.body.getReader() 的作用:
    • 获取一个可读流的读取器(ReadableStreamDefaultReader),用于后续逐步读取数据。
    • 调用 getReader() 并不会立即读取数据。
  3. 数据读取的时机:
    • 数据是在调用 reader.read() 时逐步读取的。
    • 每次读取一个数据块,直到流结束。

类比理解

可以将整个过程类比为:

  1. 打电话(fetch):

    • 你拨打电话(发起请求),等待对方接听(服务器响应)。
    • 对方接听后,电话接通(Response对象返回),但还没有开始对话。
  2. 打开话筒(getReader()):

    • 你打开话筒(获取可读流的读取器),准备听对方说话。
    • 此时还没有开始接收数据。
  3. 逐步听对方说话(reader.read()):

    • 你开始听对方说话(逐步读取数据块)。
    • 每次听到一部分内容(数据块),直到对方说完(流结束)。

总结

  • response.body.getReader() 是在 await fetch 返回 Response 对象后才执行的,但它并不会立即读取数据。
  • 数据是在调用 reader.read() 时逐步读取的,这才是真正的流式读取。
  • 流式读取的核心是通过 reader.read() 逐步获取数据块,而不是一次性获取所有数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值