获取与请求

Fetch vs Request

我正在使用 JSON 流并尝试使用 fetch 来使用它。流每隔几秒发出一些数据。只有当流关闭服务器端时,使用 fetch 来使用流才能让我访问数据。例如:

var target; // the url.
var options = {
  method: "POST",
  body: bodyString,
} 
var drain = function(response) {
  // hit only when the stream is killed server side.
  // response.body is always undefined. Can't use the reader it provides.
  return response.text(); // or response.json();
};
var listenStream = fetch(target, options).then(drain).then(console.log).catch(console.log);

/*
    returns a data to the console log with a 200 code only when the server stream has been killed.
*/

但是,已经有几块数据发送到客户端。

浏览器 中使用受节点启发的方法,就像这样,每次发送事件时都有效:

var request = require('request');
var JSONStream = require('JSONStream');
var es = require('event-stream');

request(options)
.pipe(JSONStream.parse('*'))
.pipe(es.map(function(message) { // Pipe catches each fully formed message.
      console.log(message)
 }));

我错过了什么?我的直觉告诉我,fetch 应该能够模仿 pipe 或流功能。

原来我可以让 XHR 工作——这并没有真正回答请求与获取的问题。经过几次尝试和正确的操作顺序才能做到正确。这是抽象的代码。 @jaromanda 是对的。

var _tryXhr = function(target, data) {
  console.log(target, data);
  var xhr = new XMLHttpRequest();

  xhr.onreadystatechange = function () {
    console.log("state change.. state: "+ this.readyState);
    console.log(this.responseText);
    if (this.readyState === 4) {
      // gets hit on completion.
    }
    if (this.readyState === 3) {
       // gets hit on new event
    }
  };

  xhr.open("POST", target);
  xhr.setRequestHeader("cache-control", "no-cache");
  xhr.setRequestHeader("Content-Type", "application/json");
  xhr.send(data);   
};

response.body 使您能够以流的形式访问响应。要读取流:

fetch(url).then(response => {
  const reader = response.body.getReader();

  reader.read().then(function process(result) {
    if (result.done) return;
    console.log(`Received a ${result.value.length} byte chunk of data`);
    return reader.read().then(process);
  }).then(() => {
    console.log('All done!');
  });
});

Here's a working example of the above.

获取流比 XHR 更节省内存,因为完整响应不会在内存中缓冲,并且 result.valueUint8Array 使其对二进制数据更有用。如果你想要文字,你可以使用 TextDecoder:

fetch(url).then(response => {
  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  reader.read().then(function process(result) {
    if (result.done) return;
    const text = decoder.decode(result.value, {stream: true});
    console.log(text);
    return reader.read().then(process);
  }).then(() => {
    console.log('All done!');
  });
});

Here's a working example of the above.

很快TextDecoder将成为一个转换流,让你可以做到response.body.pipeThrough(new TextDecoder()),这更简单,并允许浏览器优化。

至于您的 JSON 案例,流式 JSON 解析器可能有点庞大和复杂。如果您可以控制数据源,请考虑使用由换行符分隔的 JSON 块的格式。这真的很容易解析,大部分工作都依赖于浏览器的 JSON 解析器。 Here's a working demo,可以在较慢的连接速度下看到好处。

我也written an intro to web streams, which includes their use from within a service worker. You may also be interested in a fun hack that uses JavaScript template literals to create streaming templates.