是否有可能通过coffeescript理解从回调中收集结果?

时间:2013-04-17 19:42:13

标签: coffeescript list-comprehension for-comprehension

假设我有一些对象数组,每个对象都有一些异步readValue函数,它接受回调作为其参数,当该值可用于此对象时将触发该函数。

我的目标是计算每个对象的所有值,并使用这些值返回数组。

首先出现在我脑海中的是

calculateValues = (sources, callback) ->
    counter = 0
    length = sources.length
    result = []

    for source in sources
        source.readValue (value) ->
            result.push value
            counter++
            callback result if counter is length

由于readValue方法是异步的,因此调用它的函数也是异步的。当所有值都在result数组中时,将执行callback函数。

但这一切对我来说似乎都很混乱。这是coffeescript真正强大的领域。即使用较少的代码进行理解,是否可以编写此函数?如果它是同步的那就没关系。

1 个答案:

答案 0 :(得分:0)

不幸的是,CoffeeScript对这些涉及异步代码的问题没有多大帮助(除了拥有更简洁的函数语法,实际上非常好)。

您的代码有效,但有一点需要注意:results数组中值的顺序与sources中的源顺序不匹配。这是一个小型工作代码段,它使用setTimeout和一个随机数来获得所需的不可预测的异步行为:

calculateValues = (sources, callback) ->
  counter = 0
  length = sources.length
  result = []

  for source in sources
    source.readValue (value) ->
      result.push value
      counter++
      callback result if counter is length

sources = for i in [1..5]
  do (i) ->
    readValue: (cb) -> 
      setTimeout (-> cb "Value #{i}"), Math.random() * 1000

calculateValues sources, (results) -> 
  console.log "results", results

jsFiddle

示例输出:

results ["Value 2", "Value 5", "Value 1", "Value 3", "Value 4"]

如果你想保留这个排序,这是一个非常简单的修复,但是这展示了如何正确获取异步代码。

幸运的是,有更好的方法可以借助其他工具来表达这种结构。我建议使用像Async.js这样的简单库来帮助同步事物。这是使用async.parallel和Node使用function(err, value)形式的两个参数回调的惯例重写的相同片段(以及一些Underscore.js的小帮助,你可以很容易地将它转换为原生CS)如果你不想要它):

calculateValues = (sources, callback) ->
  funcs = _.pluck sources, 'readValue'
  async.parallel funcs, callback

sources = for i in [1..5]
  do (i) ->
    readValue: (cb) -> 
      setTimeout (-> cb null, "Value #{i}"), Math.random() * 1000

calculateValues sources, (err, results) -> 
  console.log "results", results

jsFiddle

输出:

results ["Value 1", "Value 2", "Value 3", "Value 4", "Value 5"]