6

我使用 async for 在使用 node.js 处理来自进程的输出流方面取得了巨大成功,但我正在努力获得一些我希望可以与浏览器fetchAPI“正常工作”的东西。

这非常适合异步处理来自进程的输出流块:

for await (const out of proc.child.stdout) {
  ...
}

(当然在这里的异步函数上下文中)

我试图在浏览器中做类似的事情,我想在数据从服务器发送给我的同时访问数据。

for await (const chunk of (await fetch('/data.jsonl')).body) {
  console.log('got', chunk);
}

Uncaught TypeError: (intermediate value).body is not async iterable这在 Chrome ( )中不起作用。

对于我的用例,这不是必需的,所以我现在只是let data = await (await fetch(datapath)).text();在我的客户端代码中使用。这类似于在等待的获取中使用 of.json()而不是.text(),因此在浏览器接收到整个响应之前不会开始任何处理。由于显而易见的原因,这并不理想。

我在看Oboe.js (我认为相关的 impl 就附近),它几乎可以处理这个问题,但它的内部结构相当丑陋,所以看起来这可能是目前唯一的方法?

如果没有实现异步迭代(意味着还不能使用 async for),难道没有另一种方法可以实际使用 ReadableStream 吗?

4

3 回答 3

9

不幸的是,尽管在规范中,但尚未实现异步可迭代支持。相反,您可以手动迭代,如规范中的此示例所示。(我将在此答案中将示例转换为异步/等待您。)

const reader = response.body.getReader();
const { value, done } = await reader.read();

if (done) {
  console.log("The stream was already closed!");
} else {
  console.log(value);
}

您可以使用递归或循环重复执行此操作,如在另一个示例中:

async function readAllChunks(readableStream) {
  const reader = readableStream.getReader();
  const chunks = [];
  
  let done, value;
  while (!done) {
    ({ value, done } = await reader.read());
    if (done) {
      return chunks;
    }
    chunks.push(value);
  }
}

console.log(await readAllChunks(response.body));
于 2020-05-31T23:14:07.170 回答
4

根据规范,ReadableStream诸如 fetch-API 之类的Response.body确实有一个getIterator方法。由于某种原因,它本身不是异步可迭代的,您必须明确调用该方法:

const response = await fetch('/data.json');
if (!response.ok)
    throw new Error(await response.text());
for await (const chunk of response.body.getIterator()) {
    console.log('got', chunk);
}
于 2020-05-31T20:23:40.903 回答
2

我相信 2020 年中期的现状是 async for 还不能在 fetch 主体上工作。

https://github.com/whatwg/streams/issues/778这个问题似乎有浏览器的跟踪错误,并且它们都没有实现功能。

我目前不知道.body使用fetch.

执行问题中隐含的任务的标准方法是使用 websocket。

于 2020-05-31T19:18:15.520 回答