Как избежать неявного "возврата" в coffeescript в условных выражениях?

Я реализую функцию, которая имеет отложенное значение для возврата, и внутри функции у меня есть много вложенных условных выражений:

например:.

deferred = Q.defer()
FS.readFile("foo.txt", "utf-8", (error, text) ->
    if error
      deferred.reject(new Error(error))
    else
      deferred.resolve(text)
)
return deferred.promise

который будет скомпилирован в:

var deferred;

deferred = Q.defer();

FS.readFile("foo.txt", "utf-8", function(error, text) {
  if (error) {
    --> return <-- deferred.reject(new Error(error));
  } else {
    --> return <-- deferred.resolve(text);
  }
});

return deferred.promise;

Мне нужен только последний возврат, но не возвращается if/else (т.е. → return < - в скомпилированном коде)

Как я могу избежать такого поведения (неявные возвращения там, где они не нужны) компилятора coffeescript?

Ответ 1

Coffeescript автоматически возвращает результат последних выражений, поэтому, если вы не хотите, чтобы он возвращал результаты if, вам нужно добавить еще одно выражение. В этом случае просто добавьте return.

FS.readFile "foo.txt", "utf-8", (error, text) ->
  if error
    deferred.reject new Error(error)
  else
    deferred.resolve text
  return

Кроме того, error уже является объектом error, поэтому вы можете просто отклонить его напрямую.

deferred.reject(error)

Ответ 2

Вы не можете, точно. Вы можете либо игнорировать их, когда они не нужны (что наиболее часто используется), либо предоставить явную альтернативу, добавив дополнительный оператор в конце функции. Я думаю, что попытка сделать это все время в вашей базе кода ведет борьбу против языка, который вы не можете выиграть, поэтому моя личная рекомендация просто принимает неявное возвращение г-на Ашкенаса и продолжает ваш веселый путь.

fs.readFile "foo.txt", "utf-8", (error, text) ->

  # postfix style if statement here avoids the else
  # of course, the value returned you may not like, so 
  # you probably won't use this style, but my boilerplate for
  # error handling is
  # return callback(error) if error

  return deferred.reject(new Error(error)) if error
  deferred.resolve(text)

  # Here you can add an explicit return like
  return

  # or some other expression
  null

  # or 'this' in cases where chainability might be nice
  this

  # or so you don't accidentally delete this statement later thinking it is
  # useless
  return null

любая из этих форм будет работать, но на практике я не вижу их обычно

Ответ 3

Я всегда делаю это так:

f = ->
  deferred = Q.defer()
  FS.readFile ..., ( error, text ) ->
    return deferred.reject error if error?
    deferred.resolve text
  return deferred.promise

первый return должен остановить выполнение, а не возвращать значение.

вы по-прежнему получаете дополнительный (и бессмысленный) return в своем JS из последней строки обратного вызова; чтобы избежать этого, добавьте дополнительный return null (или просто return, если вы этого захотите).

Я не уверен, что мне нравится неявная вставка в CoffeeScript; можно утверждать, что "явный лучше, чем неявный". Кроме того, можно утверждать, что первый return не должен быть return, а другим ключевым словом, например, stop или finish или somesuch.

как несвязанный боковой элемент, я не заметил никаких заметных преимуществ при использовании promises. напротив, я нашел их довольно навязчивыми в своем коде, что с этими deferred и другими понятиями, которые ставятся поверх асинхронного программирования.