使用大数据处理XMLHttpRequest响应

时间:2016-05-24 00:41:25

标签: javascript json rest google-chrome firefox

使用Chrome,我设置了XMLHttpRequest

const xhr = new XMLHttpRequest();
xhr.open(method, url, true);
...
xhr.onreadystatechange = () => {
    if (xhr.readyState === XMLHttpRequest.DONE) {
      if (isStatusCodeSuccess(xhr.status)) {
        // handle response;
      } else {
        // handle error
      }
    }
};
xhr.addEventListener('progress', event => {
    console.log(event.loaded, event.target.response.length);
});
xhr.send(data);

在某些时候,我请求一些JSON数据,其总大小约为295MB未压缩/ 5.8 MB压缩。不幸的是,当成功调用以下代码时,响应是一个空字符串。

使用progress事件监听器,我可以看到响应被chunk正确处理,直到某一点。以下是它生成的控制台日志的摘录:

32768 32768
4639135 4639135
7376739 7376739
11525403 11525403
...
261489180 261489180
264684030 264684030
267880247 267880247
271037819 0
274232442 0
277428774 0
...
304018210 0
309230213 0
310445469 0

看起来Chrome上有字符串/分配限制,但我没有收到任何错误。

在firefox上,我收到以下错误:InternalError: allocation size overflow

我尝试将结果存储起来,但我无法排空"作为属性的Xml Http Request对象是只读的。

浏览器中变量的官方限制是什么?我找不到正式答案,只是一些实验答案Javascript string size limit: 256 MB for me - is it the same for all browsers?

有没有办法解决此问题并处理大型POST结果?除了使用WebSocket。

我在考虑:

  • 用于流式传输数据的特定内容类型,例如application/octet-stream
  • 按块处理数据的特定参数,如range标题,尽管我提取的内容不是静态的(随时间变化)
  • 已知算法减少JSON响应的长度,我可以通过数据块解压缩数据块以避免达到上述限制

1 个答案:

答案 0 :(得分:2)

您可以尝试使用Fetch API,这是使用直接承诺的XMLHttpRequest的改进版本。它具有流式传输响应体的功能,而不是将整个身体响应缓冲为文本。

基本上,使用progress事件,您会在每个块上调用,但xhr响应会继续将响应累积为文本,从而达到内存限制。

使用Fetch API,您可以在收到的字节到达时读取它们:

const consume = responseReader => {
    return responseReader.read().then(result => {
        if (result.done) { return; }

        // do something with the current chunk
        const chunk = result.value;

        return consume(responseReader);
    });
}

// Perform the request and consume response stream
fetch(url).then(response => {
    return consume(response.body.getReader());
})
.catch(console.log.bind(console));

有关详细信息,请参阅此文章:Fetch (or the undeniable limitations of XHR)

仅在Chrome 43和Edge 14编写时支持通过Fetch API流式传输响应正文。 Cf compatibility table