在 javascript 中异步使用分块数据

Posted

技术标签:

【中文标题】在 javascript 中异步使用分块数据【英文标题】:Consuming chunked data asyncrhonously in javascript 【发布时间】:2018-08-18 19:16:57 【问题描述】:

我有一个 (GET) 端点,它以块的形式发送数据 (Transfer-Encoding: chunked)。数据采用 JSON 编码并逐行发送。

有没有办法在 javascript 中(或使用某些 JavaScript 库)以异步方式使用此端点发送的数据?

明确地说,我知道如何执行异步GET,但我希望GET 请求不等待整个数据传输,而是在数据到达时逐行读取.例如,当这样做时:

curl  http://localhost:8081/numbers

下面的行在可用时一一显示(我制作的示例服务器在发送一行和第二个之间等待一秒钟)。

"age":1,"name":"John"
"age":2,"name":"John"
"age":3,"name":"John"
"age":4,"name":"John"

我想在浏览器中重现 curl 的相同行为。我不想让用户等到所有数据都可用才能显示任何内容。

【问题讨论】:

未来的答案可能是developer.mozilla.org/en-US/docs/Web/API/Streams_API 谢谢!这就是为什么我在任何地方都找不到这个问题的答案。 Streams_API 看起来不会很快出现在 Firefox 中,但 ReadableStream 已经可以使用 Fetch API。你可能会觉得 this article on how to handle streams with Fetch API 很有趣。 该死!我希望在重新实现端点以使用服务器发送的事件之前看到你的答案:) 我要试试ReadableStream 对,你可以在服务器端节省一些工作量和 websockets 库依赖。 【参考方案1】:

感谢Dan 和Redu,我能够使用Fetch API 组合一个增量使用数据的示例。需要注意的是,这在 Internet Explorer 上不起作用,并且必须由用户在 Firefox 中启用:

   /** This works on Edge, Chrome, and Firefox (from version 57). To use this example
    navigate to about:config and change

    - dom.streams.enabled preference to true
    - javascript.options.streams to true


    See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
*/

fetch('http://localhost:8081/numbers').then(function(response) 

  console.log(response);

  const reader = response.body.getReader();

  function go() 
    reader.read().then(function(result) 
      if (!result.done) 
        var num = JSON.parse(
          new TextDecoder("utf-8").decode(result.value)
        );
        console.log(
          "Got number " + num.intVal
        );        
        go ();
      
    )
  

  go ();
)

完整示例(带有服务器)在at my sandbox 可用。我发现将这个版本与不使用fetch API 的this one 进行比较可以说明XMLHttpRequest 的局限性。

【讨论】:

很高兴看到您使用ReadStream 解决了这个问题。只需一个快速提醒;与 Haskell 不同,在 JS 中,在生产代码中使用递归可能会变得很危险,因为如果您有 200K+ 块要读取,您的调用堆栈最终可能会被炸毁。因此,如果您提前知道块数,您不妨用reader.read() 承诺填充该大小的数组,然后通过减少数组、对承诺进行排序来链接它们的.then() 阶段。只是一个想法。 感谢Redu的提醒。我花了太多时间做 Haskell :) 请注意,不能保证body 流将在一次读取中为您提供完整的块 (***.com/questions/57412098/…)。使用 NDJSON 可能会更好(缓冲解码的文本,直到你点击换行符,然后解析缓冲区中的 JSON 直到那时)。 @Vidar 你的回答几乎涵盖了每个用例,但我很难将 ndjson 解析应用到我的读者,你有任何使用示例吗? @moxched 这可能会有所帮助:github.com/deanhume/streams

以上是关于在 javascript 中异步使用分块数据的主要内容,如果未能解决你的问题,请参考以下文章

javascript异步编年史,从“纯回调”到Promise

Clojurescript:使用核心/异步通道分块处理请求

Javascript 和 Phonegap 插件之间的异步通信

Aliyun OSS SDK 异步分块上传导致应用异常退出

C++ - 如何分块文件以进行同时/异步处理?

回顾ajax