how to handle implicit return in coffeescript when using async.js - coffeescript

i'm trying to get
testFunction: () ->
console.log "testFunction"
async.series(
(->
console.log "first"
),
(->
console.log "second"
)
)
i've also tried to no success
testFunction: () ->
console.log "testFunction"
async.series(
(->
console.log "first"
return undefined
),
(->
console.log "second"
return undefined
)
)
to run, i would expect console output of "testFunction", "first", "second" but I'm getting "testFunction", "second" and it seems like there is a problem with coffeescript's use of implicit returns, (I guess).
Attached is a screen shot of the javascript output compiled from the above coffeescript.

Every function that does work for async needs to take a callback as its only argument.
one = (callback) ->
console.log "one"
callback()
two = (callback) ->
console.log "two"
callback()
testFunction: () ->
console.log "testFunction"
async.series [one, two], (error) ->
console.log "all done", error

You've got a number of problems. The first is that you're not passing the correct arguments to async.series. It expects:
async.series([functions...], callback)
while you're calling
async.series(function, function)
Since the length attribute of the first function is undefined, it assumes its an empty array and skips straight to the "callback" (second function). It sounds like you may want to pass an array of two functions and omit the callback.
The second problem is that functions passed to async.series must call a callback in order for progression to continue. The callback is the first argument to each function:
testFunction: () ->
console.log "testFunction"
async.series([
((next) ->
console.log "first"
next()
),
((next) ->
console.log "second"
next()
)
])
async ignores the return value of most (all?) functions that you pass to it.

Related

What would cause SingleEmitter.onSuccess() to generate a NoSuchElement exception?

I have a Single flow organized like this:
getSomething() // returns Single<>
.flatMap(something -> {
// various things
return Single.defer( () -> {
// various other things
return Single.<SomeType>create(emitter -> {
// some more stuff
someCallbackApi(result -> {
if (result.isError()) {
emitter.onError( result.getCause() );
} else {
// guaranteed non-null data
emitter.onSuccess( result.getData() ); // this generates NoSuchElement
}
});
});
})
.retryWhen( ... )
.flatMap( data -> handle(data) )
.retryWhen( ... );
})
.retryWhen( ... )
.onErrorResumeNext(error -> process(error))
.subscribe(data -> handleSuccess(data), error -> handleError(error));
In test cases, the callback api Single successfully retries a number of times (determined by the test case), and every time on the last retry, the call to emitter.onSuccess() generates the exception below. What is going on? I haven't been able to restructure or change the downstream operators or subscribers to avoid the problem.
java.util.NoSuchElementException: null
at io.reactivex.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:116)
at io.reactivex.subscribers.SerializedSubscriber.onComplete(SerializedSubscriber.java:168)
at io.reactivex.internal.operators.flowable.FlowableRepeatWhen$WhenReceiver.onComplete(FlowableRepeatWhen.java:118)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.drainLoop(FlowableFlatMap.java:426)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.drain(FlowableFlatMap.java:366)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onComplete(FlowableFlatMap.java:338)
at io.reactivex.internal.operators.flowable.FlowableZip$ZipCoordinator.drain(FlowableZip.java:210)
at io.reactivex.internal.operators.flowable.FlowableZip$ZipSubscriber.onNext(FlowableZip.java:381)
at io.reactivex.processors.UnicastProcessor.drainFused(UnicastProcessor.java:363)
at io.reactivex.processors.UnicastProcessor.drain(UnicastProcessor.java:396)
at io.reactivex.processors.UnicastProcessor.onNext(UnicastProcessor.java:458)
at io.reactivex.processors.SerializedProcessor.onNext(SerializedProcessor.java:103)
at io.reactivex.internal.operators.flowable.FlowableRepeatWhen$WhenSourceSubscriber.again(FlowableRepeatWhen.java:171)
at io.reactivex.internal.operators.flowable.FlowableRetryWhen$RetryWhenSubscriber.onError(FlowableRetryWhen.java:76)
at io.reactivex.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onError(SingleToFlowable.java:67)
at io.reactivex.internal.operators.single.SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver.onError(SingleFlatMap.java:116)
at io.reactivex.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onError(FlowableSingleSingle.java:97)
at io.reactivex.subscribers.SerializedSubscriber.onError(SerializedSubscriber.java:142)
at io.reactivex.internal.operators.flowable.FlowableRepeatWhen$WhenReceiver.onError(FlowableRepeatWhen.java:112)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.checkTerminate(FlowableFlatMap.java:567)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.drainLoop(FlowableFlatMap.java:374)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.drain(FlowableFlatMap.java:366)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:606)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672)
at io.reactivex.internal.subscriptions.EmptySubscription.error(EmptySubscription.java:55)
at io.reactivex.internal.operators.flowable.FlowableError.subscribeActual(FlowableError.java:40)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
at io.reactivex.internal.operators.flowable.FlowableZip$ZipCoordinator.drain(FlowableZip.java:249)
at io.reactivex.internal.operators.flowable.FlowableZip$ZipSubscriber.onNext(FlowableZip.java:381)
at io.reactivex.processors.UnicastProcessor.drainFused(UnicastProcessor.java:363)
at io.reactivex.processors.UnicastProcessor.drain(UnicastProcessor.java:396)
at io.reactivex.processors.UnicastProcessor.onNext(UnicastProcessor.java:458)
at io.reactivex.processors.SerializedProcessor.onNext(SerializedProcessor.java:103)
at io.reactivex.internal.operators.flowable.FlowableRepeatWhen$WhenSourceSubscriber.again(FlowableRepeatWhen.java:171)
at io.reactivex.internal.operators.flowable.FlowableRetryWhen$RetryWhenSubscriber.onError(FlowableRetryWhen.java:76)
at io.reactivex.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onError(SingleToFlowable.java:67)
at io.reactivex.internal.operators.single.SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver.onError(SingleFlatMap.java:116)
at io.reactivex.internal.disposables.EmptyDisposable.error(EmptyDisposable.java:78)
at io.reactivex.internal.operators.single.SingleError.subscribeActual(SingleError.java:42)
at io.reactivex.Single.subscribe(Single.java:3603)
at io.reactivex.internal.operators.single.SingleFlatMap$SingleFlatMapCallback.onSuccess(SingleFlatMap.java:84)
at io.reactivex.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:114)
at io.reactivex.subscribers.SerializedSubscriber.onComplete(SerializedSubscriber.java:168)
at io.reactivex.internal.operators.flowable.FlowableRetryWhen$RetryWhenSubscriber.onComplete(FlowableRetryWhen.java:82)
at io.reactivex.internal.subscriptions.DeferredScalarSubscription.complete(DeferredScalarSubscription.java:134)
at io.reactivex.internal.operators.single.SingleToFlowable$SingleToFlowableObserver.onSuccess(SingleToFlowable.java:62)
at io.reactivex.internal.operators.single.SingleCreate$Emitter.onSuccess(SingleCreate.java:67)
Solved:
Many thanks to #dano for pointing out the retryWhen behavior when used with Single. In this case, the outermost retryWhen operator had a bad terminating condition, roughly like:
.retryWhen(errors -> errors.zipWith( Flowable.range(1, maxRetries), ...)
.flatMap( zipped -> {
if (zipped.retryCount() <= maxRetries) {
return Flowable.just(0L);
}
return Flowable.error( new Exception() );
})
...Flowable.range() will complete when it has generated the last number, which will cause the Single to emit NoSuchElement. Just bumping the count argument to Flowable.range() by one is enough to fix the problem:
.retryWhen(errors -> errors.zipWith( Flowable.range(1, maxRetries + 1), ...)
.flatMap( zipped -> {
if (zipped.retryCount() <= maxRetries) {
return Flowable.just(0L);
}
return Flowable.error( new Exception() );
})
This is happening because of the way you implemented the callback you passed to retryWhen. The retryWhen docuementation states (emphasis mine):
Re-subscribes to the current Single if and when the Publisher returned
by the handler function signals a value.
If the Publisher signals an onComplete, the resulting Single will
signal a NoSuchElementException.
One of the Flowable instances you're returning inside of the calls to retryWhen is emitting onComplete, which leads to the NoSuchElementException.
Here's a very simple example that produces the same error:
Single.error(new Exception("hey"))
.retryWhen(e -> Flowable.just(1))
.subscribe(System.out::println, e -> e.printStackTrace());
The stacktrace this produces starts with this, same as yours:
java.util.NoSuchElementException
at io.reactivex.internal.operators.flowable.FlowableSingleSingle$SingleElementSubscriber.onComplete(FlowableSingleSingle.java:116)
at io.reactivex.subscribers.SerializedSubscriber.onComplete(SerializedSubscriber.java:168)
at io.reactivex.internal.operators.flowable.FlowableRepeatWhen$WhenReceiver.onComplete(FlowableRepeatWhen.java:118)
You don't include any of your code from inside the retryWhen calls, so I can't say exactly what you did wrong, but generally you want to chain whatever you do to the Flowable that is passed in. So my example above would look like this, if we really wanted to retry forever:
Single.error(new Exception("hey"))
.retryWhen(e -> e.flatMap(ign -> Flowable.just(1)))
.subscribe(System.out::println, e -> e.printStackTrace());

Atom package - setInterval not calling the function

I'm currently working on a package for atom which involves drawing a curve on a canvas. For whatever reason the following code logs "mouseDown" without ever logging "hi" when handleClickDown is called. I've tried without window. but still "mouseDown" is all that's logged. The handleClickDown function is called every time the canvas is clicked if that context helps at all. I'm sure I'm just not understanding something about how setInterval / coffescript works since I'm new to both atom and coffescript. Any help is appreciated.
#printhi: ->
console.log "hi"
handleClickDown: (event, element) ->
console.log "mouseDown"
#mouseDownId = window.setInterval(#printhi,100)
Edit: The following code seems to run fine
console.log "mouseDown"
#mouseDownId = setInterval(()=>
console.log "inner"
,75)
however when using a function like this it throws an error that _this.printhi is not a function
#printhi = () ->
console.log "hi"
handleClickDown: (event, element) ->
console.log "mouseDown"
#mouseDownId = setInterval(()=>
#printhi()
,75)
Ok just answering my own question here as I figured it out eventually. Turns out I was a bit confused on how # and => work in coffeescript. You actually need to remove the # from #printhi: -> so it becomes printhi: -> and then only use it when you're calling it like this #printhi().
Code below worked for me, hope someone finds this helpful
printhi: ->
console.log "hi"
handleClickDown: (event, element) ->
console.log "mouseDown"
#mouseDownId = setInterval(()=>
#printhi()
,75)

Q.defer workaround in Bluebird

I am migrating coffeeScript code from Q to Bluebird and it looks like I have been using promises all wrong, since Bluebird's documentation clearly discourages the use of Promise.defer
The simplified version of my client-server with Q is as follows:
Q = require 'q'
handleRequest = (msg) ->
console.log "Server received #{msg} \n"
deferred = Q.defer()
setTimeout () ->
deferred.resolve "bar"
, 2000
deferred.promise
handleRequest "foo"
.then (msg) ->
console.log msg
Basically I have a function with a promise that will be resolved asynchronously after 2 seconds.
When trying the same approach in Bluebird I get a TypeError saying that the Object function Promise(resolver) has no method 'then' (whole error code is at the end of this post)
Promise = require 'bluebird'
handleRequest = (msg) ->
console.log "Server received #{msg} \n"
new Promise (resolve) ->
"bar"
setTimeout () ->
Promise.resolve()
, 2000
Promise
handleRequest "foo"
.then (msg) ->
console.log msg
I don't know where I am messing it up since Bluebird's documentation for creating a new Promise seems to be just that, a function with resolve/reject functions.
I haven't been able to find any similar approach of promises creation without using promisify.
EventEmitters can do the trick but I really need to use promises in the big version.
There are some other bits of code where the same flow is used: a function where a defer is created/returned and it will be resolved/rejected at some stage.
Thank you very much in advance!!! :)
I have been struggling with this the whole morning.
Server received foo
TypeError: Object function Promise(resolver) {
if (typeof resolver !== "function") {
throw new TypeError("the promise constructor requires a resolver function");
}
if (this.constructor !== Promise) {
throw new TypeError("the promise constructor cannot be invoked directly");
}
this._bitField = 0;
this._fulfillmentHandler0 = void 0;
this._rejectionHandler0 = void 0;
this._promise0 = void 0;
this._receiver0 = void 0;
this._settledValue = void 0;
this._boundTo = void 0;
if (resolver !== INTERNAL) this._resolveFromResolver(resolver);
} has no method 'then'
Googling the error led me to this page of Bluebird's documentation.
So I understand that the async part of the code is the resolution of the promise itself, thus rewriting the code like shown below fixes this issue:
Promise = require 'bluebird'
handleRequest = (msg) ->
new Promise (resolve) ->
setTimeout () ->
resolve "bar"
, 2000
handleRequest "foo"
.then (msg) ->
console.log msg

Backbone events being fired without trigger

So I have a strange issue where my backbone events are getting fired even though they haven't been triggered yet. Essentially I'm making a note editor application. In the note itself, a user can press cmd + b to bold text, or any of the other normals. That then triggers an event which bubbles up to the AppController which should be subscribed to that event and call the correct method.
Here is the view for the note where the trigger is called:
class MeetingNote.View.NoteView extends Backbone.View
adminTemplate: _.template($('#AdminNoteTemplate').html())
normalTemplate: _.template($('#NormalNoteTemplate').html())
className: 'note'
events:
'keydown' : 'handleKeyDownsForStyling'
# all of the normal backbone stuff.... init/render/blah
handleKeyDownsForStyling: (e) ->
if #admin == true
if e.metaKey
switch e.which
when 66 then #trigger "boldSelection"
when 73 then #trigger "italicizeSelection"
when 85 then #trigger "underlineSelection"
Then here is my AppController which binds to the event when the NoteView is instantiated
class MeetingNote.View.AppController extends Backbone.View
template: _.template($('#MeetingNoteAppTemplate').html())
className: 'MeetingNoteApp'
initialize: (options) ->
#admin = options.privilege
#render()
render: ->
#$el.html(#template())
$('#container').append(#$el)
#initializeApp()
initializeApp: ->
#adminTools = new MeetingNote.View.AdminTools if #admin == true
notes = new MeetingNote.Collection.NotesCollection()
notes.fetch {
success: (collection) =>
_.each collection.models, (model) =>
note = new MeetingNote.View.NoteView {model: model, privilege: #admin}
#bindNoteEvents note if #admin == true
}
bindNoteEvents: (note) ->
note.on "boldSelection", #adminTools.boldSelection(), note
note.on "italicizeSelection", #adminTools.italicizeSelection(), note
note.on "underlineSelection", #adminTools.underlineSelection(), note
lastly, here is the #adminTools.boldSelection() function
boldSelection: ->
console.log( "yo" )
for some reason, upon page load, that console.log is being fired even though I never sent the trigger by pressing cmd + b in the note View. Anyone have any idea why a Backbone.Event would fire automatically?
This is a function call:
#adminTools.boldSelection()
#------------------------^^
This is a reference to a function:
#adminTools.boldSelection
You're supposed to hand on a reference to a function so that it can call the function later. Your bindNoteEvents should look more like this:
bindNoteEvents: (note) ->
note.on "boldSelection", #adminTools.boldSelection, note
note.on "italicizeSelection", #adminTools.italicizeSelection, note
note.on "underlineSelection", #adminTools.underlineSelection, note
# No parentheses here --------------------^^^^^^^^^^^^^^^^^^

Iced coffee script with multiple callbacks

I'm using Iced coffescript with upshot js when I am refreshing multiple data sources. The refresh method has TWo call backs one for success and one for error and I want to wait for each call to make either callback.
I can't see how to do this with idced coffescript without making an additional function. My question is - is there a more elegant way that I can defer to one of multiple callbacks?
This is the code I have currently:
refreshMe = (key, value, result) =>
value.refresh(
(success)=>
result success
,
(fail, reason, error)=>
result undefined, fail
)
#refresh = () =>
success={}
fail={}
await
for key, value of #dataSources
refreshMe key, value, defer success[key], fail[key]
This is the only way I have found to do it too. I'm using it in Backbone and wrap (for example) a model's #save function with an #icedSave:
# An IcedCoffeescript friendly version of save
icedSave: (callback) ->
#save {},
success: (model, response) -> callback(true, model, response)
error: (model, response) -> callback(false, model, response)
Here's some code I use for converting Promises .then (-> onSuccess), (-> onError) to errbacks (err, result) ->:
# You can write like this:
await value.refresh esc defer e, result
# onError - function to be called when promise rejected.
# onSuccess - function to be called when promise is fulfilled.
module.exports = esc = (onError, onSuccess) ->
util = require 'util'
return (result) ->
if util.isError result
# Always send back an error to first handler.
onError? result
else if onSuccess?
console.log onSuccess, result
# `await fn esc done, defer result`
onSuccess? result
else
# `await fn esc done`
onError? null, result
You could modify the esc function a bit to handle multiple arguments for each callback.
iced.Rendezvous lib is made explicitly for this case: return at the first of multiple callbacks. From the docs:
Here is an example that shows off the different inputs and outputs of
a Rendezvous. It does two parallel DNS lookups, and reports only when
the first returns:
hosts = [ "okcupid.com", "google.com" ];
ips = errs = []
rv = new iced.Rendezvous
for h,i in hosts
dns.resolve hosts[i], rv.id(i).defer errs[i], ips[i]
await rv.wait defer which
console.log "#{hosts[which]} -> #{ips[which]}"