асинхронная карта в coffeescript - PullRequest
2 голосов
/ 28 января 2012

Есть ли элегантный способ асинхронного сопоставления объекта или массива в coffeescript?(Или javascript.)

Представьте, что у меня есть некоторые вещи в объекте:

things = 
  x: 
    ...
  y:
    ...
  z:
    ...

thingCount = 3

Я хочу создать метод, который будет обрабатывать каждую из этих вещей и возвращать обработанный объект.Процесс должен сделать асинхронный вызов, чтобы получить некоторую информацию о каждой вещи.Сначала я попытался просто просмотреть все свойства, например, так:

processThings = (callback) ->

  processedThings = {}
  count = 0

  for key,val in things

    asyncJob key,val (err,result) ->

      if err
        callback error
      else
        # PROBLEM: key has the incorrect value here
        processedThings[key] = result      
        count += 1
        if count == thingCount
          callback null,processedThings

Проблема в том, что значение ключа изменяется в цикле.Поэтому мое решение состоит в том, чтобы создать подфункцию так, чтобы ключевая переменная содержалась в его закрытии:

processThings = (callback) ->

  processedThings = {}
  count = 0

  processThing = (key,val) ->

    asyncJob key,val (err,result) ->

      if err
        callback error
      else
        processedThings[key] = result      
        count += 1
        if count == thingCount
          callback null,processedThings

  processThing key,val for key,val of things

Но, черт возьми, это точно fugly .Есть ли предпочтительный шаблон для этого?

1 Ответ

5 голосов
/ 28 января 2012

CoffeeScript покрывает это ключевым словом do, описанным в конце Циклы и понимания :

При использовании цикла JavaScript для генерации функций обычно вставляютзакрывающая оболочка, чтобы гарантировать, что переменные цикла закрыты, и все сгенерированные функции не просто разделяют конечные значения.CoffeeScript предоставляет ключевое слово do, которое немедленно вызывает переданную функцию и передает любые аргументы.

for filename in list
  do (filename) ->
    fs.readFile filename, (err, contents) ->
      compile filename, contents.toString()

Его можно применить к вашему коду как:

processThings = (callback) ->

  processedThings = {}
  count = 0

  for key,val in things

    # add this to close over `key`
    do (key) ->

      asyncJob key,val (err,result) ->

        if err
          callback error
        else
          processedThings[key] = result      
          count += 1
          if count == thingCount
            callback null,processedThings
...