lowerkey
lowerkey

Reputation: 8325

How to return value from an async call

I have the following function in coffeescript:

newEdge: (fromVertexID, toVertexID) ->
    edgeID = this.NOID
    @client.methodCall('ubigraph.new_edge', [fromVertexID, toVertexID], (error, value) ->
        if(error)
            console.log('ubigraph.new_edge error: ' + error)
        edgeID = value
    )
    edgeID

where @client.methodCall refers to the xmlrpc library. My question is how to return value as edgeID. Do I use a callback for that?

If so, should the callback look something like this: ?

# callback is passed the following parameters:
# 1. error - an error, if one occurs
# 2. edgeID - the value of the returned edge id
newEdge: (fromVertexID, toVertexID, callback) ->
    @client.methodCall('ubigraph.new_edge', [fromVertexID, toVertexID], (error, value) ->
        if(error)
            console.log('ubigraph.new_edge error: ' + error)
        edgeID = value
        callback(error, value)
    )

Upvotes: 2

Views: 518

Answers (1)

mu is too short
mu is too short

Reputation: 434616

Yes, callbacks are the usual solution for asynchronous calls, sometimes you have callbacks calling callbacks calling callbacks, callbacks all the way down. I'd probably do it a little differently though:

newEdge: (fromVertexID, toVertexID, on_success = ->, on_error = ->) ->
    @client.methodCall('ubigraph.new_edge', [fromVertexID, toVertexID], (error, edge_id) ->
        if(error)
            console.log('ubigraph.new_edge error: ' + error)
            on_error(error)
        else
            on_success(edge_id)
    )

The main difference is that mine has separate success and error callbacks so that the caller can handle these conditions separately, separate callbacks for different conditions is a common approach so it should be familiar to most people. I also added default no-op callbacks so that the callbacks are optional but the main method body can pretend that they've always been supplied.

If you don't like using four arguments then you could use "named" arguments for the callbacks:

newEdge: (fromVertexID, toVertexID, callbacks = { }) ->
    @client.methodCall('ubigraph.new_edge', [fromVertexID, toVertexID], (error, edge_id) ->
        if(error)
            console.log('ubigraph.new_edge error: ' + error)
            callbacks.error?(error)
        else
            callbacks.success?(edge_id)
    )

Using an object/hash for the callbacks lets you use the existential operator instead of no-ops to make the callbacks optional.


Aaron Dufour notes that a single callback is the usual pattern in Node.js so your original approach would be a better fit for node.js:

newEdge: (fromVertexID, toVertexID, callback = ->) ->
    @client.methodCall('ubigraph.new_edge', [fromVertexID, toVertexID], (error, edge_id) ->
        if(error)
            console.log('ubigraph.new_edge error: ' + error)
        callback(error, edge_id)
    )

Upvotes: 3

Related Questions