Back Pressure on fetch() не работает в Google Chrome
У меня возникла проблема с ответом от моего сервера WebFlux с помощью нового API Streams.
Я вижу через Curl (с помощью --limit-rate
), что сервер замедляется, как ожидалось, но когда я пытаюсь уничтожить тело в Google Chrome (64.0.3282.140), он не замедляется, как он должен. На самом деле Chrome загружает и буферизирует около 32 мегабайт с сервера, хотя только около 187 кБ передается на 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];
}
}));
}
В соответствии с спецификация для потоков,
Если стратегия не указана, поведение по умолчанию будет таким же, как и CountQueuingStrategy с отметкой высокой воды 1.
Так что это должно замедлить обещание, возвращаемое consumer(item)
, разрешается очень медленно, правильно?
Ответы
Ответ 1
Глядя на поддержку противодавления в API Streams, кажется, что информация о противодавлении передается в цепочке потоков, а не по сети. В этом случае мы можем предполагать неограниченную очередь где-то, и это объясняет поведение, которое вы видите.
Этот другой вопрос github предполагает, что информация о противодавлении действительно останавливается на уровне TCP - они просто прекращают чтение из сокета TCP, который, в зависимости от в текущем размере TCP-TCP/конфигурации TCP означает, что буферы будут заполнены, а затем будет выполняться управление потоком TCP. Как говорится в этой проблеме, они не могут установить размер окна вручную, и они должны позволить TCP-стекю обрабатывать вещи оттуда.
HTTP/2 поддерживает управление потоками на уровне протокола, но я не знаю, используют ли реализации браузера это с помощью API Streams.
Я не могу объяснить разницу в поведении, которую вы видите, но я думаю, что вы, возможно, слишком много читаете в поддержке Backpressure, и это работает как ожидается в соответствии со спецификацией.