3

假设我有一组对象,每个对象都有一些异步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函数将被执行。

但这一切对我来说似乎很混乱。这是咖啡脚本真正强大的领域。是否可以使用更少的带有理解的代码来编写这个函数?如果它是同步的,那没关系。

4

1 回答 1

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"]
于 2013-04-18T06:19:51.837 回答