fetch()上的Back Pressure在Google Chrome中无效

Rya*_*ren 10 javascript google-chrome reactive-programming reactive-streams spring-webflux

我无法通过JavaScript的新Streams API从我的WebFlux服务器中获取响应.

我可以通过Curl(在帮助下--limit-rate)看到服务器正在按预期放慢速度,但是当我尝试在Google Chrome(64.0.3282.140)中使用正文时,它并没有像它应该的那样减速.实际上,即使只传递了大约187 kB,Chrome也会从服务器下载并缓冲大约32 MB write().

我的JavaScript有问题吗?

async function fetchStream(url, consumer) {
    const response = await fetch(url, {
        headers: {
            "Accept": "application/stream+json"
        }
    });
    const decoder = new TextDecoder("utf-8");
    let buffer = "";
    await response.body.pipeTo(new WritableStream({
        async write(chunk) {
            buffer += decoder.decode(chunk);
            const blocks = buffer.split("\n");
            if (blocks.length === 1) {
                return;
            }
            const indexOfLastBlock = blocks.length - 1;
            for (let index = 0; index < indexOfLastBlock; index ++) {
                const block = blocks[index];
                const item = JSON.parse(block);
                await consumer(item);
            }
            buffer = blocks[indexOfLastBlock];
        }
    }));
}
Run Code Online (Sandbox Code Playgroud)

根据Streams的规范,

如果未提供策略,则默认行为将与具有高水位标记1的CountQueuingStrategy相同.

所以它应该减慢做出consumer(item)决定所带来的承诺非常缓慢,对吧?

Bri*_*zel 4

查看Streams API 中的背压支持,似乎背压信息是在 Streams 链内而不是通过网络进行通信的。在这种情况下,我们可以假设某个地方有一个无界队列,这可以解释您所看到的行为。

另一个github 问题表明,背压信息确实停止在 TCP 级别 - 它们只是停止从 TCP 套接字读取,这取决于当前的 TCP 窗口大小/TCP 配置,意味着缓冲区将被填充,然后 TCP 流量控制启动正如这个问题所述,他们无法手动设置窗口大小,并且必须让 TCP 堆栈从那里处理事情。

HTTP/2 支持协议级别的流量控制,但我不知道浏览器实现是否通过 Streams API 来利用它。

我无法解释您所看到的行为差异,但我认为您可能在此处的背压支持中阅读了太多内容,并且这根据规范按预期工作。