Reputation: 8386
I am implementing a function that has deferred value to return and within the function I have many nested conditional expressions:
e.g.:
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
which than will be compiled into:
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;
I need only the last return, but not the if/else returns (i.e. --> return <-- in the compiled code)
How can I avoid such a behavior (implicit returns where they are do not needed) of the coffeescript compiler?
Upvotes: 13
Views: 4737
Reputation: 145994
You can't, exactly. You can either ignore them when not needed (which is the most common thing to do) or provide an explicit alternative by adding an additional statement at the end of the function. I think trying to do this all the time in your code base is fighting a war against the language you cannot win, so my personal recommendation is just accept Mr. Ashkenas's implicit return and go on your merry way.
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
any of those forms will work, but in practice I don't see these commonly
Upvotes: 2
Reputation: 3652
i always do it like this:
f = ->
deferred = Q.defer()
FS.readFile ..., ( error, text ) ->
return deferred.reject error if error?
deferred.resolve text
return deferred.promise
the first return
is there to stop execution, not to return a value.
you still get an additional (and meaningless) return
in your JS from the last line of the callback; to avoid that one, insert an additional return null
(or simply return
if you prefer that).
i'm not sure i like CoffeeScript's implicit return
insertion; it might be claimed that 'explicit is better than implicit'. also, it could be argued that the first return
shouldn't be a return
but another keyword, like, say, stop
or finish
or somesuch.
as an unrelated sidenote, i haven't observed any noticeable advantage when using promises. to the contrary, i found them quite intrusive in my code, what with those deferred
s and other concepts that are put on top of asynchronous programming.
Upvotes: 0
Reputation: 161457
Coffeescript automatically returns the result of the last expressions, so if you don't want it to return the results of the if
then you need to add another expressions. In this case, just add return
.
FS.readFile "foo.txt", "utf-8", (error, text) ->
if error
deferred.reject new Error(error)
else
deferred.resolve text
return
Also, error
is already an Error
object, so you can just reject it directly.
deferred.reject(error)
Upvotes: 12