【问题标题】:Stream JSON with RxJS Observable使用 RxJS Observable 流式传输 JSON
【发布时间】:2015-12-19 17:42:33
【问题描述】:

我试图了解一些关于 RxJs 的事情。我想做的是使用一些 JSON 数据,并在数据进入时立即开始在 DOM 上呈现该数据。我已经设置了流请求、响应和显示。它的每一个输出都很好,但它是一次性完成的,而不是随着时间的推移。

我想在数据进入时开始在页面上显示数据,而不是等待整个文件完成然后立即显示,这会产生很长的等待时间。

//Cache the selector
var $resultList = $('.results');

//Gets the JSON (this will not be a static file,just for testing)
var requestStream = Rx.Observable.just("/results.json");

var responseStream = requestStream
    .flatMap(function(requestUrl) {
            return Rx.Observable.fromPromise(jQuery.getJSON(requestUrl))
             });

var displayStream = responseStream.subscribe(
    function(response) {
    //This maps to a Handlebars Template and puts it on the DOM
    $resultList.html(compiledTemplate(response)); 
            },
            function(err) {
                    console.log('Error: %s', err);
             },
             function() {
                    console.log('Completed');
             });




//Sample of the data from the JSON file
Object{
    beginIndex: "1"
    catId: "111"
    endIndex: "1"
    products: Array[100]

}

【问题讨论】:

  • 您已经正确设置了所有内容,但是,getJSON 会立即检索所有内容。从这个意义上说, responseStream 不是一个流,它是一个完全形成的对象。从 jQuery.getJSON 解析的承诺只是页面的整个响应。仅当您同时从多个来源(results.json、results2.json 等)加载数据时,您的代码才会产生您正在寻找的操作。
  • 有没有办法开始将单个 JSON 文件转换为一个对象,并在该对象进入时开始循环遍历该对象上的数组?我正在寻找一种在数据传入和处理时以增量方式流式传输数据的方法。
  • 你真的依赖于浏览器的行为。响应以具有统一大小的块的形式出现,但可以在数据对象中的任何位置开始和结束: [chunk 1, data: "[{object 1},{[ob] [chunk 2, data: "[{ject2} {[object3...etc.... broswer 收集这些并将它们按正确的顺序排列。现在您要问的是如何破解 http 协议,这太过分了。如果你想逐个对象解析这个对象,你需要使用 websocket 连接到你的服务器并一个一个地发出每个成员,这比单个 get 调用更流畅。
  • 敲最后一个答案,它可能会将所有内容分成一大块发送,就我们的目的而言,它会在瞬间到达。您仍在寻找类似 websocket 的行为。 (例如:socket.io
  • 那么如果流式传输不是一个好的路由,那么分块呢?因此,取出该数组中的前 10 个并将其发送出去以进行显示。然后接下来的10个等等。所以更像是在更小的块中缓冲/处理。

标签: javascript json rxjs reactivex


【解决方案1】:

如果我理解得很好,有两点需要说明:

  1. 您需要找到一种方法从该文件中获取对象流 当你读完那个文件时,而不是一个大对象 (I want to start showing the data on the page as its coming in)。这 其机制首先取决于源的结构(文件和文件读取机制) 比在 Rxjs 上(每一行都是一个可以导致信息的对象 显示等?)。一旦你有了“最小可显示信息单元”,你就可以在需要时使用 Rxjs 来缓冲/处理它(你想为每个对象或每 100 个对象显示一些东西,还是删除不必要的属性等?)
  2. 您需要逐步更新您的显示 随着新数据的到来。这意味着你需要类似的东西 $resultList.html($resultList.html() + compiledTemplate(response)); 将新编译的html 附加到旧的。

更新:为了分块一个数组,你可以看看这个 jsfiddle:http://jsfiddle.net/429vw0za/

var ta_result = document.getElementById('ta_result');

function emits ( who, who_ ) {return function ( x ) {
 who.innerHTML = [who.innerHTML, who_ + " emits " + JSON.stringify(x)].join("\n");
};}

function fillArrayWithNumbers(n) {
        var arr = Array.apply(null, Array(n));
        return arr.map(function (x, i) { return {prop1: i, prop2:i, prop3:i} });
    }

var sampleObj = {
    beginIndex: "1",
    catId: "111",
    endIndex: "1",
    products: fillArrayWithNumbers(100)
}

console.log('sampleObj', sampleObj);

var result$ = Rx.Observable
  .from(sampleObj.products)
  .bufferWithCount(10)
  .map(function(mini_array){return {
  beginIndex: sampleObj.beginIndex,
  catId: sampleObj.catId,
  endIndex: sampleObj.endIndex,
  products: mini_array
  }})
  .do(emits(ta_result, 'result'));

result$.subscribe(function(){    });

然后,您将拥有从大小为 100 的数组中提取的大小为 10 的数组的对象流。

【讨论】:

  • 您好,感谢您的回复。 1.) 我需要遍历该对象上的 products 数组,并为 Handlebars 模板拉入该对象上的其他 3 个属性。所以会消耗一个大对象。
  • 您的数组是否如此庞大以至于将其分块是有意义的(或者一个项目的处理时间如此之长)?使用 Rxjs,您可以轻松地将数组分块为“迷你”数组流。因此,您可以获得该大对象并输出您通过当前代码的数组调整版本使用的迷你数组流。这对你有用吗?
  • 是的,那将是完美的。如果我可以流式传输要显示的该数组的块,那么我可以更快地在页面上获取产品,而不是等待同时显示所有 100 个产品。
  • 已发布使用 Rxjs 回答。但是,我想知道你是否真的必须使用 Rxjs。你可以直接切片你的数组并做一个简单的循环。所以你在这里根本不需要流,只需要常规的 Promise 和常规的同步代码。另外:flatMap接受承诺,所以你可以直接写return jQuery.getJSON(requestUrl)
  • 在 RxJS 5 中,bufferWithCount 更改为 bufferCount。 github.com/ReactiveX/rxjs/blob/master/MIGRATION.md。麻烦...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-24
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-01
相关资源
最近更新 更多