TL;DR: 我预计
fetch
API 在发送完整的 HTTP 响应标头后即可解析,但由于某种原因需要 8000 毫秒。
我有一个使用 Express 来响应 HTTP 请求的服务器。它不会给出单一响应,而是随着时间的推移发出多次
write
调用以提供状态更新。在浏览器中,HTTP 请求是使用 fetch API 发出的。响应主体是异步迭代的。
除了一个问题之外,所有这些都工作正常。等待 fetch 调用响应的时间约为 8 秒。我知道服务器发送第一个块不需要8秒。我什至与 XHR 进行了比较,XHR 触发进度事件的时间不到 50 毫秒。我可以做些什么来使初始获取承诺更快地解决吗?
app.post("/bulk-update", (req, res) => {
buildTask(req.body, 5, (status) => {
const completed = status.success + status.error;
const remaining = status.total - completed;
if (remaining === 0) {
res.write(`${JSON.stringify(status)}\n`);
res.end();
return;
}
if (completed % 10 === 0) {
res.write(`${JSON.stringify(status)}\n`);
}
});
});
let jobStartTime = Date.now();
const response = await fetch(`/bulk-update`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body,
});
console.log("end request", Date.now() - jobStartTime); // <-- this is logging 8000ms
const stream = response.body.pipeThrough(new TextDecoderStream());
let buffer = "";
for await (const chunk of stream) {
buffer += chunk;
const lines = buffer.split("\n");
buffer = lines.at(-1);
for (let i = 0; i < lines.length - 1; i++) {
const line = lines[i];
const status = JSON.parse(line);
updateProgress(status);
}
if (buffer.trim().length > 0) {
const status = JSON.parse(buffer);
updateProgress(status);
}
}
通过将服务器响应中的
Content-Type
标头设置为 text/event-stream
,我能够更快地解析提取。看来如果fetch
没有看到这个标头,解析需要更长的时间。
app.post("/bulk-update", (req, res) => {
res.setHeader('Content-Type', 'text/event-stream'); // <-- this is the line the fixed it
res.setHeader('Connection', 'keep-alive'); // Not needed for quick fetch, just is accurate
buildTask(req.body, 5, (status) => {
const completed = status.success + status.error;
const remaining = status.total - completed;
if (remaining === 0) {
res.write(`${JSON.stringify(status)}\n`);
res.end();
return;
}
if (completed % 10 === 0) {
res.write(`${JSON.stringify(status)}\n`);
}
});
});
我在Fetch Standard中没有看到任何关于此的内容。我还在 Chrome 上进行了测试,并且无需标头即可快速解析。据我所知,这是专门针对 Firefox 的实现细节。