1

I am having an issue figuring out how to make an array of functions with different parameters. I am using coffeescript and async but I think it is a problem with my understanding of javascript.

I want to create an array of functions with different tasks.

names = ['Jeff', 'Maria', 'Steve']
tasks = []

for name in names
  tasks.push (callback)=>
      @controller.get_person name, (person) =>
        callback(null, person)

async.parallel(tasks, cb)

The problem is that the task is getting called with Steve (always the one that is last in the array) three times. How do I make it so that there is one task per each name?

Alexis
  • 23,545
  • 19
  • 104
  • 143
  • possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Bergi Feb 05 '13 at 20:05
  • possible duplicate of [Closure Scope not captured? — Coffeescript](http://stackoverflow.com/questions/11996218/closure-scope-not-captured-coffeescript) – mu is too short Feb 05 '13 at 20:16
  • @Bergi offers a general JavaScript solution that will also apply to CoffeeScript, my duplicate includes the CoffeeScript-specific `do` keyword. Take your pick. – mu is too short Feb 05 '13 at 20:17

2 Answers2

1

Try changing for name in names to names.forEach (name)=>. Be careful of the space after forEach.

names = ['Jeff', 'Maria', 'Steve']
tasks = []

names.forEach (name)=>
  tasks.push (callback)=>
      @controller.get_person name, (person) =>
        callback(null, person)

async.parallel(tasks, cb)
Plynx
  • 11,341
  • 3
  • 32
  • 33
1

Actually, in this particular case, you should probably make use of async's map:

getPerson = (name, callback) =>
  @controller.get_person name, (person) ->
    callback(null, person)

async.map names, getPerson, (err, persons) ->
  // Do stuff with persons

Note that if your @controller.get_person method followed the node practice of passing any errors as the first parameter to the callback, this would suffice:

async.map names, @controller.get_person, (err, persons) ->
  // Do stuff with persons

Something to keep in mind, perhaps.

Linus Thiel
  • 38,647
  • 9
  • 109
  • 104
  • very nice! Thank you. The first way works beautifully. The second way looks awesome. However, in the second way, the `@controller` does not seem to get passed through to the `map` function. What I mean by this is that the @ seems to get rebound and looses the reference to `controller`. Is there a way to fix this? – Alexis Feb 06 '13 at 17:26
  • @Scoop: Yes, you need to declare `get_person` with the fat arrow (`=>`) so it will always be bound to the object (in the class definition of whatever `@controller` is). – Linus Thiel Feb 06 '13 at 17:29