I wouldn't take this approach unless you also detain and then release the command using the command map - your listener here won't be cleaned up automatically, and the command will be held in memory by that and so it won't be disposed of and then the handler could potentially fire again the future.
Unless there's something magical about Responder that is causing it to be cleaned up automatically?
Wow, 3 replies in less than 10 minutes, that's awesome, but now
I'm more confused because the 3 replies are different :)
[ EDIT, 5 replieeees !!!! please let me write :) ] I didn't know
about commandMap.detain and release, and I thought the same as
I know updating the model from the command is ok, but is OK to have
a listener in the command? I thought commands was only
I see this approach in Cairngorm (commands implements IResponder
and they have a result and fault listener).
@Michal how can be our command released if they have a listener?
this case in particular is a bit confusing to me because the
listener is added to "responder" which is part of the command, but
the results come from the service, so I think there must be another
listener in another place... maybe it doesn't matter because the
service cleans everything for us. I can see and advantage in this
design, each command that uses the service can use it's own result.
Probably this is cleaner and faster (we don't need to map another
command for the result, destroy this command, dispatch a new event
in our service, create the new command).
Is this a best practice in Robotlegs? are you listening the
results of your services inside your commands?
if not, what is the best practice for this?
I want to recall that this is not my code, I found it in a
And after seeing your replies I see it's OK, but it's not so
common, I mean, you are not using this pattern in your projects am
I can think only in another alternative:
1) Command executes the service
2) The service listen the result
3a) The service dispatch an event mapped to another command
3b) The service updates the model
4a) The new command updates the model
What is the pattern your are following?
Do you see any pros and cons of listening the result inside our
I use a model to call service. Service returns Promise
(Responder-like). Command calls model method to call. In other
approach you can call service from the command and when service get
a result it (service) dispatches command with the result, which can
be saved in a model. So there are 2 approaches I'd recommend.
OK, I've read those discussion, Promises, AsyncTokens, etc.
Thanks Michal !
Now this is my conclusion for the Best Practice:
Service must be a singleton
Service returns Promises (AsyncToken if you are using Flex and
RemoteObject for example) so you can differentiate every response
even when you have one Service.
Commands call services, receive the Pomise, and listen for the
result in the Promise (assign a Responder to the AsyncToken).
The command updates the model, dispatch an event, or anything
you want with the result.
we don't need to use "detain" and "release" in our command
because our command add a listener to the Promise (AsyncToken), so
Promise has a reference to command, and Promise is saved from GC
because has a reference on the Service which is never GC because is
In the worst case, (if the service never release the Promise
reference) we need to remove the listener to the Promise in our
command (so at least our command is GC)
I see that approach very similar to how commands works in
Cairngorm. I'm a bit confused for that, I thought Cairngorm was the
worst framework :(
I can't see the advantage of executing a service from a command,
releasing the command, and creating a new command from the service
when the result is ready.
Can you explain why or when that approach is better?
Respec to to calling service from your model, are you listening
the service from your model too? isn't that a "bad" thing?
detain and release are relatively late additions to the CommandMap, so it's likely that early demos won't refer to them.
Even if you are using a listener which should prevent GC, I would still use detain and release because these communicate your intent. They make it immediately obvious to the next developer (or yourself in six months time) that you intended this Command to not be short-lived.
I would also clean up listeners explicitly, rather than hope for GC, again because it communicates your intent.
We spend nearly all our time reading and thinking about code, and very little time writing it, so the code that *reads* the clearest is a good goal I think.
Regarding the 'why bother with 2 commands' side - the answer is simply that you should split up responsibilities appropriately. It's very possible (I have this in my code) to have single command that calls a service, and then a series of different possible results, which then mean that you need variation in how you respond to those results.
Personally my own set up is that a Command calls a service, the service is injected with a factory that handles any results, the factory then updates models and so on and the models release update events which the view uses (via mediators) to update itself.
But it all depends on the details of your application.
Whatever you do, do it mindfully and express your intention clearly in your code, and you'll be winning :)
You are right @stray about writing clean and clear code, I do
that at really, but is good to know what is necessary and what not
About the pattern, it's true that exists a lot of way for doing
the same thing, this happens all the time, but I'm always paranoid
about performance, and even more in Flas/Flex which is full of
memory leaks taht we can't control (more in old players).
That's why I'm always trying to code with the "best practices".
Do you have a sample of the code, or an open source project to
see it better @stray? I'm not catching your factory idea.
// Maybe that could be a good idea, to have a repository with
projects/apps written in Robotlegs.
The only part that I'm not happy with is the use of the check
against 'null' to decide whether the builder hit an error. I'm sure
there is a better way to do this, but I haven't worked out what
that is yet! Any input there gratefully received...
why you are unhappy with that?
if you want an onResult and onFault but synchoronous maybe you can
throw an error in your Builder (in the Factory, the try is
onResult, the catch is onFault)