在Bacon FRP流中汇编分页的ajax数据

时间:2015-04-30 14:06:26

标签: javascript frp bacon.js

我正在使用Bacon.js学习FRP,并希望从流中的分页API组装数据。

使用数据的模块有一个消费API,如下所示:

// UI module, displays unicorns as they arrive
beautifulUnicorns.property.onValue(function(allUnicorns){
  console.log("Got "+ allUnicorns.length +" Unicorns");
  // ... some real display work
});

组装数据的模块每次获取新数据集时都会从API请求顺序页面并push到流中:

// beautifulUnicorns module
var curPage = 1
var stream = new Bacon.Bus()
var property = stream.toProperty()
var property.onValue(function(){}) # You have to add an empty subscriber, otherwise future onValues will not receive the initial value. https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-property-updated

var allUnicorns = [] // !!! stateful list of all unicorns ever received. Is this idiomatic for FRP?

var getNextPage = function(){
  /* get data for subsequent pages.
     Skipping for clarity */
}

var gotNextPage = function (resp) {
  Array.prototype.push.apply(allUnicorns, resp) // just adds the responses to the existing array reference
  stream.push(allUnicorns)
  curPage++
  if (curPage <= pageLimit) { getNextPage() }
}

如何以能够为我提供所有曾获得过的独角兽的完整列表的方式订阅该流?这是flatMap还是类似的?我不认为我需要一个新的流,但我不知道。对不起,我是FRP思维方式的新手。要清楚,组装阵列是有效的,只是感觉我没有做惯用的事情。

我没有使用jQuery或其他ajax库,所以这就是为什么我没有使用Bacon.fromPromise

您也可能想知道为什么我的消费模块需要整个集合而不仅仅是增量更新。如果它只是附加可能正常的行,但在我的情况下,它是一个无限滚动,如果两者都应该绘制数据:1。数据可用 2.区域在屏幕上。

1 个答案:

答案 0 :(得分:1)

以下是使用flatMapfold的解决方案。在处理网络时,您必须记住数据的返回顺序与发送请求的顺序不同 - 这就是折叠和地图组合的原因。

var pages = Bacon.fromArray([1,2,3,4,5])
var requests = pages.flatMap(function(page) {
  return doAjax(page)
  .map(function(value) {
    return {
      page: page,
      value: value
    }
  })
}).log("Data received")

var allData = requests.fold([], function(arr, data) {
  return arr.concat([data])
}).map(function(arr) {
  // I would normally write this as a oneliner
  var sorted = _.sortBy(arr, "page")
  var onlyValues = _.pluck(sorted, "value")
  var inOneArray = _.flatten(onlyValues)
  return inOneArray
})

allData.log("All data")

function doAjax(page) {
  // This would actually be Bacon.fromPromise($.ajax...)

  // Math random to simulate the fact that requests can return out
  // of order
  return Bacon.later(Math.random() * 3000, [ 
    "Page"+page+"Item1", 
    "Page"+page+"Item2"])
}

http://jsbin.com/damevu/4/edit