Best practice for calling asynchronous functions?

classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Best practice for calling asynchronous functions?

Mark Carter
In my app, I make a wide variety of XML-RPC calls. Now, to avoid having to add/remove listeners all over the place, I've created a class (facade?) with functions like:

function save(xml:XML, successFunc:Function, failureFunc:Function):void;
function load(id:String, successFunc:Function, failureFunc:Function):void;

Note, the class' state does not change when any of these functions are called.

The class makes the necessary XML-RPC call and listens to the appropriate events before calling the relevant success or failure function. The class guarantees that either the successFunc or the failureFunc will be called at some point (but never both).

This makes my calling code very neat:

save(myXML, function(id:String):void {
    Alert.show("Successfully saved XML using id: " + id);
    // now do the next step
}, function(msg:String):void {
    Alert.show("Failed to save because: " + msg);
    // now rollback
});

One obvious drawback of this is that its not so easy to add multiple listeners to, say, the save operation. But, in my situation, I never need to.

What say you all - good or bad practice?
Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Paul A.
----- Original Message -----
From: "Mark Carter" <[hidden email]>
To: <[hidden email]>
Sent: Wednesday, December 10, 2008 8:34 AM
Subject: [flexcoders] Best practice for calling asynchronous functions?


>
> In my app, I make a wide variety of XML-RPC calls. Now, to avoid having to
> add/remove listeners all over the place, I've created a class (facade?)
> with
> functions like:
>
> function save(xml:XML, successFunc:Function, failureFunc:Function):void;
> function load(id:String, successFunc:Function, failureFunc:Function):void;
>
> Note, the class' state does not change when any of these functions are
> called.
>
> The class makes the necessary XML-RPC call and listens to the appropriate
> events before calling the relevant success or failure function. The class
> guarantees that either the successFunc or the failureFunc will be called
> at
> some point (but never both).
>
> This makes my calling code very neat:
>
> save(myXML, function(id:String):void {
>    Alert.show("Successfully saved XML using id: " + id);
>    // now do the next step
> }, function(msg:String):void {
>    Alert.show("Failed to save because: " + msg);
>    // now rollback
> });
>
> One obvious drawback of this is that its not so easy to add multiple
> listeners to, say, the save operation. But, in my situation, I never need
> to.

I would have thought it was very easy to add multiple listeners for the save
operation - just have the single successFunc call multiple functions. The
real problem may be that writing inline functions could make your code
difficullt to follow if they get too complex - I'd probably use inline
functions only for trivial cases.

Effectively you've replaced event listeners with callback functions. I don't
see the harm in it and I know a lot of people like using callbacks rather
than full blown event handling.
It does look quite neat and enforce cleaning up listeners.

Paul


>
> What say you all - good or bad practice?
> --
> View this message in context:
> http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20930596.html
> Sent from the FlexCoders mailing list archive at Nabble.com.

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Marco Catunda
In reply to this post by Mark Carter
Mark,

I've used to the same approach you describe but I didn't implemet
failureFunc. This facade, in my case, detect a failure and display
a message error. This approach take an advantage that you don't take
care any more for failures and it will always be treat in the same way.

This is a example method in my facade

public function formDeleteAccount( listener: Function ): Operation

To call this method you can use

formDeleteAccount( <handler> ).send( <params> )

The send method return a AsyncToken and you can add more "listener"
or put other params token for handler function.

There is other methods like it:

public function filterByText( listener: Function, text: String ): AsyncToken

In this case, we use the compiler to force the correct params. I like
this second approach
and we will convert all the code to use it.

If you have an interesting, I can send you all the code. But believe,
I don't know if it is the
best practice, but, for my problem, it run very well.

--
Marco Catunda

On Wed, Dec 10, 2008 at 6:34 AM, Mark Carter <[hidden email]> wrote:

>
> In my app, I make a wide variety of XML-RPC calls. Now, to avoid having to
> add/remove listeners all over the place, I've created a class (facade?) with
> functions like:
>
> function save(xml:XML, successFunc:Function, failureFunc:Function):void;
> function load(id:String, successFunc:Function, failureFunc:Function):void;
>
> Note, the class' state does not change when any of these functions are
> called.
>
> The class makes the necessary XML-RPC call and listens to the appropriate
> events before calling the relevant success or failure function. The class
> guarantees that either the successFunc or the failureFunc will be called at
> some point (but never both).
>
> This makes my calling code very neat:
>
> save(myXML, function(id:String):void {
> Alert.show("Successfully saved XML using id: " + id);
> // now do the next step
> }, function(msg:String):void {
> Alert.show("Failed to save because: " + msg);
> // now rollback
> });
>
> One obvious drawback of this is that its not so easy to add multiple
> listeners to, say, the save operation. But, in my situation, I never need
> to.
>
> What say you all - good or bad practice?
> --
> View this message in context:
> http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20930596.html
> Sent from the FlexCoders mailing list archive at Nabble.com.
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Amy-28
In reply to this post by Paul A.
--- In [hidden email], "Paul Andrews" <paul@...> wrote:
>
> ----- Original Message -----
> From: "Mark Carter" <code@...>
> To: <[hidden email]>
> Sent: Wednesday, December 10, 2008 8:34 AM
> Subject: [flexcoders] Best practice for calling asynchronous
functions?
>
>
> >
> > In my app, I make a wide variety of XML-RPC calls. Now, to avoid
having to
> > add/remove listeners all over the place, I've created a class
(facade?)
> > with
> > functions like:
> >
> > function save(xml:XML, successFunc:Function,
failureFunc:Function):void;
> > function load(id:String, successFunc:Function,
failureFunc:Function):void;
> >
> > Note, the class' state does not change when any of these
functions are
> > called.
> >
> > The class makes the necessary XML-RPC call and listens to the
appropriate
> > events before calling the relevant success or failure function.
The class
> > guarantees that either the successFunc or the failureFunc will be
called

> > at
> > some point (but never both).
> >
> > This makes my calling code very neat:
> >
> > save(myXML, function(id:String):void {
> >    Alert.show("Successfully saved XML using id: " + id);
> >    // now do the next step
> > }, function(msg:String):void {
> >    Alert.show("Failed to save because: " + msg);
> >    // now rollback
> > });
> >
> > One obvious drawback of this is that its not so easy to add
multiple
> > listeners to, say, the save operation. But, in my situation, I
never need
> > to.
>
> I would have thought it was very easy to add multiple listeners for
the save
> operation - just have the single successFunc call multiple
functions. The
> real problem may be that writing inline functions could make your
code
> difficullt to follow if they get too complex - I'd probably use
inline
> functions only for trivial cases.
>
> Effectively you've replaced event listeners with callback
functions. I don't
> see the harm in it and I know a lot of people like using callbacks
rather
> than full blown event handling.
> It does look quite neat and enforce cleaning up listeners.

Another way to handle it is with a token.  The token "rides" the
event, so there's no cleanup to be done...Once the event is handled
the reference to it goes away, and so does the token and its
responders.

http://flexdiary.blogspot.com/2008/11/more-thoughts-on-remoting.html

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Mark Carter
Thanks for all the responses.

I hadn't really looked into the ASyncToken until now. However, for me it seems that using the ASyncToken would be limited to the implementation of the, for example, save(XML, Function, Function) method.

The calling code doesn't need to know about it. In my opinion this is neater than something like:

var asyncToken:ASyncToken = save(xml);
asyncToken.addResponder(...

Also, I don't like adding responders after the call has been made. I know it works, but still...

Maybe I should start a new topic for this next question, but...

...in my implementation, I create a new HTTPService for each call. Any ideas how (in)efficient this is?  As you can imagine, it keeps the implementation much simpler. No need for the ASyncToken. Just add new listeners each time a call is made. Everything is garbage collected..... Oh, hang on, what keeps a reference to the HTTPService?????
Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Amy-28
--- In [hidden email], Mark Carter <code@...> wrote:
>
>
> Thanks for all the responses.
>
> I hadn't really looked into the ASyncToken until now. However, for
me it
> seems that using the ASyncToken would be limited to the
implementation of
> the, for example, save(XML, Function, Function) method.
>
> The calling code doesn't need to know about it.

Right.  The calling code doesn't need to do anything different.  The
change is inside your method.

Here's an example:

/* Execute method.  If calling object passes in result and fault
handlers,
                        those are used.  Otherwise, the defaults are
used. */
                public static function execute(categoryID:int=-1,
searchString:String=null,
                        resultHandler:Function=null,
faultHandler:Function=null):void{
                        if (_channels.channels.length==0) {
                                throw new Error('No endpoint
specified for GetCategories command Remote Object');
                        }
                        //set up remote object
                        _ro.channelSet=_channels;
                        _ro.destination = 'AMF_Category';
                        _ro.source = 'AMF_Category';
                        //set up a token so we can tell the result of
this call from other calls
                        var token:AsyncToken=_ro.getServicesCount
(categoryID>-1?categoryID: null, searchString);
                        //assign the result and fault handlers from
the calling object
                        token.addResponder(new Responder(!
(resultHandler==null)?resultHandler:countLoaded,
                                                            !
(faultHandler==null)? faultHandler: loadFailed));
                }
                /* trace out the return since we don't know
where to put it */
                private static function countLoaded
(e:ResultEvent):void{
                        trace(e.result.toString() + ' profiles');
                }
                private static function loadFailed(e:FaultEvent):void{
                        trace(e.fault);
                }

> In my opinion this is neater
> than something like:
>
> var asyncToken:ASyncToken = save(xml);
> asyncToken.addResponder(...

Suit yourself.  You weren't satisfied with what you were using.  I
offered an alternative.
 
> Also, I don't like adding responders after the call has been made.
I know it
> works, but still...

Me neither.  I'm not sure why they built it this way, but
unfortunately that's what we have.  Just don't dispatch an event in
between LOL.

> Maybe I should start a new topic for this next question, but...
>
> ...in my implementation, I create a new HTTPService for each call.
Any ideas
> how (in)efficient this is?  

I'm thinking it's pretty bad.

> As you can imagine, it keeps the implementation
> much simpler. No need for the ASyncToken. Just add new listeners
each time a
> call is made. Everything is garbage collected..... Oh, hang on,
what keeps a
> reference to the HTTPService?????

Good question.  What did you do with all the old eventListeners you
were complaining about in your original post?

Reply | Threaded
Open this post in threaded view
|

RE: Re: Best practice for calling asynchronous functions?

Tracy Spratt
In reply to this post by Mark Carter
"...adding responders after the call has been made..." That is not
actually what happens.  The call is not made at that line, just set up.
I recall reading a fuller explanation, but didn't follow the internals
well enough to repeat it.

 

Tracy

 

________________________________

From: [hidden email] [mailto:[hidden email]] On
Behalf Of Amy
Sent: Thursday, December 11, 2008 11:47 AM
To: [hidden email]
Subject: [flexcoders] Re: Best practice for calling asynchronous
functions?

 

--- In [hidden email] <mailto:flexcoders%40yahoogroups.com>
, Mark Carter <code@...> wrote:
>
>
> Thanks for all the responses.
>
> I hadn't really looked into the ASyncToken until now. However, for
me it
> seems that using the ASyncToken would be limited to the
implementation of
> the, for example, save(XML, Function, Function) method.
>
> The calling code doesn't need to know about it.

Right. The calling code doesn't need to do anything different. The
change is inside your method.

Here's an example:

/* Execute method. If calling object passes in result and fault
handlers,
those are used. Otherwise, the defaults are
used. */
public static function execute(categoryID:int=-1,
searchString:String=null,
resultHandler:Function=null,
faultHandler:Function=null):void{
if (_channels.channels.length==0) {
throw new Error('No endpoint
specified for GetCategories command Remote Object');
}
//set up remote object
_ro.channelSet=_channels;
_ro.destination = 'AMF_Category';
_ro.source = 'AMF_Category';
//set up a token so we can tell the result of
this call from other calls
var token:AsyncToken=_ro.getServicesCount
(categoryID>-1?categoryID: null, searchString);
//assign the result and fault handlers from
the calling object
token.addResponder(new Responder(!
(resultHandler==null)?resultHandler:countLoaded,
!
(faultHandler==null)? faultHandler: loadFailed));
}
/* trace out the return since we don't know
where to put it */
private static function countLoaded
(e:ResultEvent):void{
trace(e.result.toString() + ' profiles');
}
private static function loadFailed(e:FaultEvent):void{
trace(e.fault);
}

> In my opinion this is neater
> than something like:
>
> var asyncToken:ASyncToken = save(xml);
> asyncToken.addResponder(...

Suit yourself. You weren't satisfied with what you were using. I
offered an alternative.

> Also, I don't like adding responders after the call has been made.
I know it
> works, but still...

Me neither. I'm not sure why they built it this way, but
unfortunately that's what we have. Just don't dispatch an event in
between LOL.

> Maybe I should start a new topic for this next question, but...
>
> ...in my implementation, I create a new HTTPService for each call.
Any ideas
> how (in)efficient this is?

I'm thinking it's pretty bad.

> As you can imagine, it keeps the implementation
> much simpler. No need for the ASyncToken. Just add new listeners
each time a
> call is made. Everything is garbage collected..... Oh, hang on,
what keeps a
> reference to the HTTPService?????

Good question. What did you do with all the old eventListeners you
were complaining about in your original post?

 

Reply | Threaded
Open this post in threaded view
|

RE: Best practice for calling asynchronous functions?

Seth Hodgson
In reply to this post by Mark Carter
I haven't been following this thread, but the sample code below can actually be shortened to something like this:

    save(xml).addResponder(new AsyncResponder(handleResult, handleFault));

No AsyncToken in the code and rather than new'ing the responder, if you always want to direct results/faults to a consistent pair of handler functions you could set up the AsyncResponder earlier and just pass in a ref.

   save(xml).addResponder(saveResponder);

The only reason to actually get a ref to the returned AsyncToken is if you want to add some dynamic properties to it that will help drive your handling of the eventual async result/fault (the token - and any custom state you've tagged it with - is accessible within your result/fault callbacks when they execute).

But for scenarios like that where I want to hang onto some data from the call site, I often find it simpler to take advantage of the variable/scope capture that a closure provides by defining my result/fault callbacks as inline lambda functions rather than manually "capturing" state by copying a portion of it into properties of the AsyncToken. So something like:

    save(xml).addResponder(new AsyncResponder(
                                              function(...   , // inline result handler function
                                              function(...     // inline fault handler function
                                             ));

Rather than new'ing an HTTPService for every call you make and trying to manage adding/removing event listeners (which will prevent instances from being GC'ed) in your wrapper I'd recommend just following the first convention I list above for each call: someMethod(args).addResponder(new AsyncResponder(handleResult, handleFault));

Best,
Seth

From: [hidden email] [mailto:[hidden email]] On Behalf Of Mark Carter
Sent: Wednesday, December 10, 2008 7:23 PM
To: [hidden email]
Subject: Re: [flexcoders] Best practice for calling asynchronous functions?


Thanks for all the responses.

I hadn't really looked into the ASyncToken until now. However, for me it
seems that using the ASyncToken would be limited to the implementation of
the, for example, save(XML, Function, Function) method.

The calling code doesn't need to know about it. In my opinion this is neater
than something like:

var asyncToken:ASyncToken = save(xml);
asyncToken.addResponder(...

Also, I don't like adding responders after the call has been made. I know it
works, but still...

Maybe I should start a new topic for this next question, but...

...in my implementation, I create a new HTTPService for each call. Any ideas
how (in)efficient this is? As you can imagine, it keeps the implementation
much simpler. No need for the ASyncToken. Just add new listeners each time a
call is made. Everything is garbage collected..... Oh, hang on, what keeps a
reference to the HTTPService?????
--
View this message in context: http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20948799.html
Sent from the FlexCoders mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Josh McDonald-4
Some quick pointers (I do the framework stuff where I work):

All (afaik) network requests are queued up until the end of frame, so you
can nearly always add responders to a token...

...Except request errors, such as an invalid SOAP request. These can in some
circumstances generate Fault exceptions that never make it to the token :(

Here's some example code:

            // ...

            //This code is to catch invocation problems, since Flash has
decided to interrupt the flow of the VM for
            //FaultEvent rather than dispatch it on next frame from the
token
            operation.addEventListener(FaultEvent.FAULT,
invocationFaultHandler);

            //Send the request
            log.debug("Sending request...");
            token = operation.send();
            log.debug("...Send attempt completed");

            //Remove our invocation fault listener
            operation.removeEventListener(FaultEvent.FAULT,
invocationFaultHandler);

            //Do we need to send this info on to the token's listeners in a
frame or two?
            if (invocationFaultEvent) //Instance-level global
            {
                log.debug("There was an invoke error, which means the token
listeners aren't notified. Will redispatch to them in 250ms");
                //When we create the timer, we're using a hard listener
reference because this helper instance may otherwise be collected before
we're done!
                //So make sure to remove the handler (and kill the timer) on
firing!
                timer = new Timer(250, 1);
                timer.addEventListener(TimerEvent.TIMER,
reDispatchInvocationFault);
                timer.start();
            }

            return token;
        }

        private function invocationFaultHandler(event : FaultEvent) : void
        {
            log.error("A fault occured during invocation");
            this.invocationFaultEvent = event;
        }

        private function reDispatchInvocationFault(event : TimerEvent) :
void
        {
            //Important!
            timer.removeEventListener(TimerEvent.TIMER,
reDispatchInvocationFault);
            timer.stop();
            timer = null;

            token.mx_internal::applyFault(invocationFaultEvent);
        }


On Fri, Dec 12, 2008 at 4:08 AM, Seth Hodgson <[hidden email]> wrote:

> I haven't been following this thread, but the sample code below can
> actually be shortened to something like this:
>
>    save(xml).addResponder(new AsyncResponder(handleResult, handleFault));
>
> No AsyncToken in the code and rather than new'ing the responder, if you
> always want to direct results/faults to a consistent pair of handler
> functions you could set up the AsyncResponder earlier and just pass in a
> ref.
>
>   save(xml).addResponder(saveResponder);
>
> The only reason to actually get a ref to the returned AsyncToken is if you
> want to add some dynamic properties to it that will help drive your handling
> of the eventual async result/fault (the token - and any custom state you've
> tagged it with - is accessible within your result/fault callbacks when they
> execute).
>
> But for scenarios like that where I want to hang onto some data from the
> call site, I often find it simpler to take advantage of the variable/scope
> capture that a closure provides by defining my result/fault callbacks as
> inline lambda functions rather than manually "capturing" state by copying a
> portion of it into properties of the AsyncToken. So something like:
>
>    save(xml).addResponder(new AsyncResponder(
>                                              function(...   , // inline
> result handler function
>                                              function(...     // inline
> fault handler function
>                                             ));
>
> Rather than new'ing an HTTPService for every call you make and trying to
> manage adding/removing event listeners (which will prevent instances from
> being GC'ed) in your wrapper I'd recommend just following the first
> convention I list above for each call: someMethod(args).addResponder(new
> AsyncResponder(handleResult, handleFault));
>
> Best,
> Seth
>
> From: [hidden email] [mailto:[hidden email]] On
> Behalf Of Mark Carter
> Sent: Wednesday, December 10, 2008 7:23 PM
> To: [hidden email]
> Subject: Re: [flexcoders] Best practice for calling asynchronous functions?
>
>
> Thanks for all the responses.
>
> I hadn't really looked into the ASyncToken until now. However, for me it
> seems that using the ASyncToken would be limited to the implementation of
> the, for example, save(XML, Function, Function) method.
>
> The calling code doesn't need to know about it. In my opinion this is
> neater
> than something like:
>
> var asyncToken:ASyncToken = save(xml);
> asyncToken.addResponder(...
>
> Also, I don't like adding responders after the call has been made. I know
> it
> works, but still...
>
> Maybe I should start a new topic for this next question, but...
>
> ...in my implementation, I create a new HTTPService for each call. Any
> ideas
> how (in)efficient this is? As you can imagine, it keeps the implementation
> much simpler. No need for the ASyncToken. Just add new listeners each time
> a
> call is made. Everything is garbage collected..... Oh, hang on, what keeps
> a
> reference to the HTTPService?????
> --
> View this message in context:
> http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20948799.html
> Sent from the FlexCoders mailing list archive at Nabble.com.
>
>
>
> ------------------------------------
>
> --
> Flexcoders Mailing List
> FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
> Alternative FAQ location:
> https://share.acrobat.com/adc/document.do?docid=942dbdc8-e469-446f-b4cf-1e62079f6847
> Search Archives:
> http://www.mail-archive.com/flexcoders%40yahoogroups.comYahoo! Groups
> Links
>
>
>
>


--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Like the cut of my jib? Check out my Flex blog!

:: Josh 'G-Funk' McDonald
:: 0437 221 380 :: [hidden email]
:: http://flex.joshmcdonald.info/
:: http://twitter.com/sophistifunk
Reply | Threaded
Open this post in threaded view
|

RE: Best practice for calling asynchronous functions?

Seth Hodgson
Hi Josh,

This sounds like a bug in SOAP serialization in the Flex SDK that's generating a Fault locally on the client (no networking involved) but apparently has a bug and does so incorrectly.

Would you mind logging a bug with test case if you haven't already?

Thanks,
Seth

From: [hidden email] [mailto:[hidden email]] On Behalf Of Josh McDonald
Sent: Thursday, December 11, 2008 3:05 PM
To: [hidden email]
Subject: Re: [flexcoders] Best practice for calling asynchronous functions?

Some quick pointers (I do the framework stuff where I work):

All (afaik) network requests are queued up until the end of frame, so you can nearly always add responders to a token...

...Except request errors, such as an invalid SOAP request. These can in some circumstances generate Fault exceptions that never make it to the token :(

Here's some example code:

            // ...

            //This code is to catch invocation problems, since Flash has decided to interrupt the flow of the VM for
            //FaultEvent rather than dispatch it on next frame from the token
            operation.addEventListener(FaultEvent.FAULT, invocationFaultHandler);

            //Send the request
            log.debug("Sending request...");
            token = operation.send();
            log.debug("...Send attempt completed");

            //Remove our invocation fault listener
            operation.removeEventListener(FaultEvent.FAULT, invocationFaultHandler);

            //Do we need to send this info on to the token's listeners in a frame or two?
            if (invocationFaultEvent) //Instance-level global
            {
                log.debug("There was an invoke error, which means the token listeners aren't notified. Will redispatch to them in 250ms");
                //When we create the timer, we're using a hard listener reference because this helper instance may otherwise be collected before we're done!
                //So make sure to remove the handler (and kill the timer) on firing!
                timer = new Timer(250, 1);
                timer.addEventListener(TimerEvent.TIMER, reDispatchInvocationFault);
                timer.start();
            }

            return token;
        }

        private function invocationFaultHandler(event : FaultEvent) : void
        {
            log.error("A fault occured during invocation");
            this.invocationFaultEvent = event;
        }

        private function reDispatchInvocationFault(event : TimerEvent) : void
        {
            //Important!
            timer.removeEventListener(TimerEvent.TIMER, reDispatchInvocationFault);
            timer.stop();
            timer = null;

            token.mx_internal::applyFault(invocationFaultEvent);
        }

On Fri, Dec 12, 2008 at 4:08 AM, Seth Hodgson <[hidden email]> wrote:
I haven't been following this thread, but the sample code below can actually be shortened to something like this:

   save(xml).addResponder(new AsyncResponder(handleResult, handleFault));

No AsyncToken in the code and rather than new'ing the responder, if you always want to direct results/faults to a consistent pair of handler functions you could set up the AsyncResponder earlier and just pass in a ref.

  save(xml).addResponder(saveResponder);

The only reason to actually get a ref to the returned AsyncToken is if you want to add some dynamic properties to it that will help drive your handling of the eventual async result/fault (the token - and any custom state you've tagged it with - is accessible within your result/fault callbacks when they execute).

But for scenarios like that where I want to hang onto some data from the call site, I often find it simpler to take advantage of the variable/scope capture that a closure provides by defining my result/fault callbacks as inline lambda functions rather than manually "capturing" state by copying a portion of it into properties of the AsyncToken. So something like:

   save(xml).addResponder(new AsyncResponder(
                                             function(...   , // inline result handler function
                                             function(...     // inline fault handler function
                                            ));

Rather than new'ing an HTTPService for every call you make and trying to manage adding/removing event listeners (which will prevent instances from being GC'ed) in your wrapper I'd recommend just following the first convention I list above for each call: someMethod(args).addResponder(new AsyncResponder(handleResult, handleFault));

Best,
Seth

From: [hidden email] [mailto:[hidden email]] On Behalf Of Mark Carter
Sent: Wednesday, December 10, 2008 7:23 PM
To: [hidden email]
Subject: Re: [flexcoders] Best practice for calling asynchronous functions?


Thanks for all the responses.

I hadn't really looked into the ASyncToken until now. However, for me it
seems that using the ASyncToken would be limited to the implementation of
the, for example, save(XML, Function, Function) method.

The calling code doesn't need to know about it. In my opinion this is neater
than something like:

var asyncToken:ASyncToken = save(xml);
asyncToken.addResponder(...

Also, I don't like adding responders after the call has been made. I know it
works, but still...

Maybe I should start a new topic for this next question, but...

...in my implementation, I create a new HTTPService for each call. Any ideas
how (in)efficient this is? As you can imagine, it keeps the implementation
much simpler. No need for the ASyncToken. Just add new listeners each time a
call is made. Everything is garbage collected..... Oh, hang on, what keeps a
reference to the HTTPService?????
--
View this message in context: http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20948799.html
Sent from the FlexCoders mailing list archive at Nabble.com.



------------------------------------

--
Flexcoders Mailing List
FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
Alternative FAQ location: https://share.acrobat.com/adc/document.do?docid=942dbdc8-e469-446f-b4cf-1e62079f6847
Search Archives: http://www.mail-archive.com/flexcoders%40yahoogroups.comYahoo! Groups Links





--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Like the cut of my jib? Check out my Flex blog!

:: Josh 'G-Funk' McDonald
:: 0437 221 380 :: [hidden email]
:: http://flex.joshmcdonald.info/
:: http://twitter.com/sophistifunk

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Amy-28
In reply to this post by Tracy Spratt
--- In [hidden email], "Tracy Spratt" <tspratt@...> wrote:
>
> "...adding responders after the call has been made..." That is not
> actually what happens.  The call is not made at that line, just set
up.
> I recall reading a fuller explanation, but didn't follow the internals
> well enough to repeat it.

Regardless, the flow of the logic doesn't make much sense, especially
when someone comes behind you to maintain the code who doesn't know
much about remoting...

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Josh McDonald-4
In reply to this post by Seth Hodgson
Hi Seth,

It stems I think from the fact that the Async stuff in the SDK (AsyncToken,
IResponder impls) are a little too closely tied to Flex's underlying
remoting stuff. But I've already brought that up on the SDK dev list and it
seemed you guys are on top of that issue.

The problem is that from the SDK's point of view, there is no request.
There's no IMessage, there's nothing to wait on. However from the
application's point of view, there is.

If I'm going to go to the trouble of building a failing case and submitting
a bug, I may as well include a patch. SOAPEncoder throws an exception when
asked to build an incorrect request which is reasonable, but of course this
happens before the token is returned to the application code, and the event
is sent to the Operation (and WebService I assume) before the application
gets a chance to register its interest.

Is there a place in the SDK code where a non-visual component needs to do a
callLater() that I can copy? Do they just use the old "new Timer(1,1)"
trick?

-Josh

On Fri, Dec 12, 2008 at 9:29 AM, Seth Hodgson <[hidden email]> wrote:

> Hi Josh,
>
> This sounds like a bug in SOAP serialization in the Flex SDK that's
> generating a Fault locally on the client (no networking involved) but
> apparently has a bug and does so incorrectly.
>
> Would you mind logging a bug with test case if you haven't already?
>
> Thanks,
> Seth
>
> From: [hidden email] [mailto:[hidden email]] On
> Behalf Of Josh McDonald
> Sent: Thursday, December 11, 2008 3:05 PM
> To: [hidden email]
> Subject: Re: [flexcoders] Best practice for calling asynchronous functions?
>
> Some quick pointers (I do the framework stuff where I work):
>
> All (afaik) network requests are queued up until the end of frame, so you
> can nearly always add responders to a token...
>
> ...Except request errors, such as an invalid SOAP request. These can in
> some circumstances generate Fault exceptions that never make it to the token
> :(
>
> Here's some example code:
>
>            // ...
>
>            //This code is to catch invocation problems, since Flash has
> decided to interrupt the flow of the VM for
>            //FaultEvent rather than dispatch it on next frame from the
> token
>            operation.addEventListener(FaultEvent.FAULT,
> invocationFaultHandler);
>
>            //Send the request
>            log.debug("Sending request...");
>            token = operation.send();
>            log.debug("...Send attempt completed");
>
>            //Remove our invocation fault listener
>            operation.removeEventListener(FaultEvent.FAULT,
> invocationFaultHandler);
>
>            //Do we need to send this info on to the token's listeners in a
> frame or two?
>            if (invocationFaultEvent) //Instance-level global
>            {
>                log.debug("There was an invoke error, which means the token
> listeners aren't notified. Will redispatch to them in 250ms");
>                //When we create the timer, we're using a hard listener
> reference because this helper instance may otherwise be collected before
> we're done!
>                //So make sure to remove the handler (and kill the timer) on
> firing!
>                timer = new Timer(250, 1);
>                timer.addEventListener(TimerEvent.TIMER,
> reDispatchInvocationFault);
>                timer.start();
>            }
>
>            return token;
>        }
>
>        private function invocationFaultHandler(event : FaultEvent) : void
>        {
>            log.error("A fault occured during invocation");
>            this.invocationFaultEvent = event;
>        }
>
>        private function reDispatchInvocationFault(event : TimerEvent) :
> void
>        {
>            //Important!
>            timer.removeEventListener(TimerEvent.TIMER,
> reDispatchInvocationFault);
>            timer.stop();
>            timer = null;
>
>            token.mx_internal::applyFault(invocationFaultEvent);
>        }
>
> On Fri, Dec 12, 2008 at 4:08 AM, Seth Hodgson <[hidden email]> wrote:
> I haven't been following this thread, but the sample code below can
> actually be shortened to something like this:
>
>   save(xml).addResponder(new AsyncResponder(handleResult, handleFault));
>
> No AsyncToken in the code and rather than new'ing the responder, if you
> always want to direct results/faults to a consistent pair of handler
> functions you could set up the AsyncResponder earlier and just pass in a
> ref.
>
>  save(xml).addResponder(saveResponder);
>
> The only reason to actually get a ref to the returned AsyncToken is if you
> want to add some dynamic properties to it that will help drive your handling
> of the eventual async result/fault (the token - and any custom state you've
> tagged it with - is accessible within your result/fault callbacks when they
> execute).
>
> But for scenarios like that where I want to hang onto some data from the
> call site, I often find it simpler to take advantage of the variable/scope
> capture that a closure provides by defining my result/fault callbacks as
> inline lambda functions rather than manually "capturing" state by copying a
> portion of it into properties of the AsyncToken. So something like:
>
>   save(xml).addResponder(new AsyncResponder(
>                                             function(...   , // inline
> result handler function
>                                             function(...     // inline
> fault handler function
>                                            ));
>
> Rather than new'ing an HTTPService for every call you make and trying to
> manage adding/removing event listeners (which will prevent instances from
> being GC'ed) in your wrapper I'd recommend just following the first
> convention I list above for each call: someMethod(args).addResponder(new
> AsyncResponder(handleResult, handleFault));
>
> Best,
> Seth
>
> From: [hidden email] [mailto:[hidden email]] On
> Behalf Of Mark Carter
> Sent: Wednesday, December 10, 2008 7:23 PM
> To: [hidden email]
> Subject: Re: [flexcoders] Best practice for calling asynchronous functions?
>
>
> Thanks for all the responses.
>
> I hadn't really looked into the ASyncToken until now. However, for me it
> seems that using the ASyncToken would be limited to the implementation of
> the, for example, save(XML, Function, Function) method.
>
> The calling code doesn't need to know about it. In my opinion this is
> neater
> than something like:
>
> var asyncToken:ASyncToken = save(xml);
> asyncToken.addResponder(...
>
> Also, I don't like adding responders after the call has been made. I know
> it
> works, but still...
>
> Maybe I should start a new topic for this next question, but...
>
> ...in my implementation, I create a new HTTPService for each call. Any
> ideas
> how (in)efficient this is? As you can imagine, it keeps the implementation
> much simpler. No need for the ASyncToken. Just add new listeners each time
> a
> call is made. Everything is garbage collected..... Oh, hang on, what keeps
> a
> reference to the HTTPService?????
> --
> View this message in context:
> http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20948799.html
> Sent from the FlexCoders mailing list archive at Nabble.com.
>
>
>
> ------------------------------------
>
> --
> Flexcoders Mailing List
> FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
> Alternative FAQ location:
> https://share.acrobat.com/adc/document.do?docid=942dbdc8-e469-446f-b4cf-1e62079f6847
> Search Archives:
> http://www.mail-archive.com/flexcoders%40yahoogroups.comYahoo! Groups
> Links
>
>
>
>
>
> --
> "Therefore, send not to know For whom the bell tolls. It tolls for thee."
>
> Like the cut of my jib? Check out my Flex blog!
>
> :: Josh 'G-Funk' McDonald
> :: 0437 221 380 :: [hidden email]
> :: http://flex.joshmcdonald.info/
> :: http://twitter.com/sophistifunk
>
>
> ------------------------------------
>
> --
> Flexcoders Mailing List
> FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
> Alternative FAQ location:
> https://share.acrobat.com/adc/document.do?docid=942dbdc8-e469-446f-b4cf-1e62079f6847
> Search Archives:
> http://www.mail-archive.com/flexcoders%40yahoogroups.comYahoo! Groups
> Links
>
>
>
>


--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Like the cut of my jib? Check out my Flex blog!

:: Josh 'G-Funk' McDonald
:: 0437 221 380 :: [hidden email]
:: http://flex.joshmcdonald.info/
:: http://twitter.com/sophistifunk
Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Mark Carter
In reply to this post by Amy-28
Amy-28 wrote
Right.  The calling code doesn't need to do anything different.  The
change is inside your method.

Here's an example:
Thanks for that - its roughly what I had in mind - but its good for me to see an example.

Amy-28 wrote
> In my opinion this is neater
> than something like:
>
> var asyncToken:ASyncToken = save(xml);
> asyncToken.addResponder(...

Suit yourself.  You weren't satisfied with what you were using.  I
offered an alternative.
Maybe I wasn't being clear. I just prefer to keep any ASyncToken code out of the calling code. Having it inside the implementation is not a problem for me (other than for the other problems with it discussed in this topic). So, I don't see it as an alternative - its more of an implementation detail.

Amy-28 wrote
> As you can imagine, it keeps the implementation
> much simpler. No need for the ASyncToken. Just add new listeners
each time a
> call is made. Everything is garbage collected..... Oh, hang on,
what keeps a
> reference to the HTTPService?????

Good question.  What did you do with all the old eventListeners you
were complaining about in your original post?
My current implementation has something like:

function save(xml:XML, successFunc:Function, failureFunc:Function):void {
    var service:HTTPService = new HTTPService();
    ...
    service.addEventListener(ResultEvent.RESULT, function(evt:ResultEvent):void {
        trace("Successfully saved XML");
        successFunc();
    });
    service.send(); // called after the event listeners have been added :)
}

That's it. The successFunc and failureFunc are only scoped to the calling code's method and so should be garbage collected when the service is garbage collected.

What I don't know is when the service is garbage collected? I'm assuming not before the result or fault event is fired!
Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Mark Carter
In reply to this post by Josh McDonald-4
Josh McDonald-4 wrote
The problem is that from the SDK's point of view, there is no request.
There's no IMessage, there's nothing to wait on. However from the
application's point of view, there is.
I don't quite understand...

Wouldn't any problems before the async token is returned, be thrown as an exception from the method returning the async token? Therefore the calling code just needs to catch that exception and handle it.

The only problem with this would be if an event is generated after the async token is returned and before the responder is added. This would only be an issue in a multi-threaded environment.

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Josh McDonald-4
SOAPEncoder throws an exception, which is caught by Operation, swallowed,
and then a fault event is dispatched from the Operation instance. If you do
all your async stuff using responders because you need to know *which*
action has just finished or faulted (among other things), you never get to
hear about it.

-Josh

On Fri, Dec 12, 2008 at 2:20 PM, Mark Carter <[hidden email]> wrote:

>
>
> Josh McDonald-4 wrote:
> >
> > The problem is that from the SDK's point of view, there is no request.
> > There's no IMessage, there's nothing to wait on. However from the
> > application's point of view, there is.
> >
>
> I don't quite understand...
>
> Wouldn't any problems before the async token is returned, be thrown as an
> exception from the method returning the async token? Therefore the calling
> code just needs to catch that exception and handle it.
>
> The only problem with this would be if an event is generated after the
> async
> token is returned and before the responder is added. This would only be an
> issue in a multi-threaded environment.
>
>
> --
> View this message in context:
> http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20969714.html
> Sent from the FlexCoders mailing list archive at Nabble.com.
>
>
> ------------------------------------
>
> --
> Flexcoders Mailing List
> FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
> Alternative FAQ location:
> https://share.acrobat.com/adc/document.do?docid=942dbdc8-e469-446f-b4cf-1e62079f6847
> Search Archives:
> http://www.mail-archive.com/flexcoders%40yahoogroups.comYahoo! Groups
> Links
>
>
>
>


--
"Therefore, send not to know For whom the bell tolls. It tolls for thee."

Like the cut of my jib? Check out my Flex blog!

:: Josh 'G-Funk' McDonald
:: 0437 221 380 :: [hidden email]
:: http://flex.joshmcdonald.info/
:: http://twitter.com/sophistifunk
Reply | Threaded
Open this post in threaded view
|

RE: Best practice for calling asynchronous functions?

Seth Hodgson
Right, definitely a bug in mx.rpc.soap.Operation#invokePendingCall where it invokes a helper method to dispatch fault events directly if it hits encoding errors, etc.

An example of what it should be doing can be seen in mx.rpc.soap.mxml.Operation#send:
new AsyncDispatcher(dispatchRpcEvent, [faultEvent], 1);

mx.rpc.AsyncDispatcher is a (currently @private) helper class that helps avoids Timer leaks due to overlooking cleaning up event listeners when using the old "Timer(1, 1)" idiom.

Best,
Seth

From: [hidden email] [mailto:[hidden email]] On Behalf Of Josh McDonald
Sent: Thursday, December 11, 2008 9:20 PM
To: [hidden email]
Subject: Re: [flexcoders] Best practice for calling asynchronous functions?

SOAPEncoder throws an exception, which is caught by Operation, swallowed, and then a fault event is dispatched from the Operation instance. If you do all your async stuff using responders because you need to know *which* action has just finished or faulted (among other things), you never get to hear about it.

-Josh
On Fri, Dec 12, 2008 at 2:20 PM, Mark Carter <[hidden email]> wrote:


Josh McDonald-4 wrote:
>
> The problem is that from the SDK's point of view, there is no request.
> There's no IMessage, there's nothing to wait on. However from the
> application's point of view, there is.
>
I don't quite understand...

Wouldn't any problems before the async token is returned, be thrown as an
exception from the method returning the async token? Therefore the calling
code just needs to catch that exception and handle it.

The only problem with this would be if an event is generated after the async
token is returned and before the responder is added. This would only be an
issue in a multi-threaded environment.
Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Amy-28
In reply to this post by Mark Carter
--- In [hidden email], Mark Carter <code@...> wrote:
<stuff snipped>

> Amy-28 wrote:
> >
> >> As you can imagine, it keeps the implementation
> >> much simpler. No need for the ASyncToken. Just add new listeners
> > each time a
> >> call is made. Everything is garbage collected..... Oh, hang on,
> > what keeps a
> >> reference to the HTTPService?????
> >
> > Good question.  What did you do with all the old eventListeners
you
> > were complaining about in your original post?
> >
>
> My current implementation has something like:
>
> function save(xml:XML, successFunc:Function,
failureFunc:Function):void {
>     var service:HTTPService = new HTTPService();
>     ...
>     service.addEventListener(ResultEvent.RESULT,
> function(evt:ResultEvent):void {
>         trace("Successfully saved XML");
>         successFunc();
>     });
>     service.send(); // called after the event listeners have been
added :)
> }
>
> That's it. The successFunc and failureFunc are only scoped to the
calling
> code's method and so should be garbage collected when the service
is garbage
> collected.
>
> What I don't know is when the service is garbage collected? I'm
assuming not
> before the result or fault event is fired!

My understanding is that anonymous functions _cannot_ get garbage
collected unless you use weak references when you add them.  Which
means there's a really good chance they'll get garbage collected
before they get called.

HTH;

Amy

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Mark Carter
So are you saying that, in general, anonymous functions should not be used as listeners?

If its anything like in Java, (once the calling method returned) the anonymous function would only be referenced by the event dispatcher and so (assuming weak references are not used) would only be garbage collected when the event dispatcher is garbage collected. At least, that's how I understand it.

I posted a question about this a few weeks ago, but didn't get a reply.

Amy-28 wrote
My understanding is that anonymous functions _cannot_ get garbage
collected unless you use weak references when you add them.  Which
means there's a really good chance they'll get garbage collected
before they get called.
Reply | Threaded
Open this post in threaded view
|

RE: Best practice for calling asynchronous functions?

Alex Harui
I think Amy's point is that, w/o a reference to the anonfun, you can't call removeEventListener on it.  If I do:

someObj.addEventListener("foo", function (e:Event) { ... } );

someObj will release the anonfun when it gets garbage collected.  However, until that time, all objects in the scope chain won't be collectable.  I don't know if that's the case in Java.

From: [hidden email] [mailto:[hidden email]] On Behalf Of Mark Carter
Sent: Friday, December 12, 2008 6:28 AM
To: [hidden email]
Subject: Re: [flexcoders] Best practice for calling asynchronous functions?


So are you saying that, in general, anonymous functions should not be used as
listeners?

If its anything like in Java, (once the calling method returned) the
anonymous function would only be referenced by the event dispatcher and so
(assuming weak references are not used) would only be garbage collected when
the event dispatcher is garbage collected. At least, that's how I understand
it.

I posted a question about this a few weeks ago, but didn't get a reply.

Amy-28 wrote:
>
> My understanding is that anonymous functions _cannot_ get garbage
> collected unless you use weak references when you add them. Which
> means there's a really good chance they'll get garbage collected
> before they get called.
>

--
View this message in context: http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20976648.html
Sent from the FlexCoders mailing list archive at Nabble.com.

Reply | Threaded
Open this post in threaded view
|

Re: Best practice for calling asynchronous functions?

Ralf Bokelberg-2
You can use arguments.callee to let a anonymous listener remove itself.

Cheers
Ralf.



On Fri, Dec 12, 2008 at 7:23 PM, Alex Harui <[hidden email]> wrote:

> I think Amy's point is that, w/o a reference to the anonfun, you can't call
> removeEventListener on it.  If I do:
>
>
>
> someObj.addEventListener("foo", function (e:Event) { … } );
>
>
>
> someObj will release the anonfun when it gets garbage collected.  However,
> until that time, all objects in the scope chain won't be collectable.  I
> don't know if that's the case in Java.
>
>
>
> From: [hidden email] [mailto:[hidden email]] On
> Behalf Of Mark Carter
> Sent: Friday, December 12, 2008 6:28 AM
> To: [hidden email]
> Subject: Re: [flexcoders] Best practice for calling asynchronous functions?
>
>
>
> So are you saying that, in general, anonymous functions should not be used
> as
> listeners?
>
> If its anything like in Java, (once the calling method returned) the
> anonymous function would only be referenced by the event dispatcher and so
> (assuming weak references are not used) would only be garbage collected when
> the event dispatcher is garbage collected. At least, that's how I understand
> it.
>
> I posted a question about this a few weeks ago, but didn't get a reply.
>
> Amy-28 wrote:
>>
>> My understanding is that anonymous functions _cannot_ get garbage
>> collected unless you use weak references when you add them. Which
>> means there's a really good chance they'll get garbage collected
>> before they get called.
>>
>
> --
> View this message in context:
> http://www.nabble.com/Best-practice-for-calling-asynchronous-functions--tp20930596p20976648.html
> Sent from the FlexCoders mailing list archive at Nabble.com.
>
>

------------------------------------

--
Flexcoders Mailing List
FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
Alternative FAQ location: https://share.acrobat.com/adc/document.do?docid=942dbdc8-e469-446f-b4cf-1e62079f6847
Search Archives: http://www.mail-archive.com/flexcoders%40yahoogroups.comYahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/flexcoders/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/flexcoders/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:[hidden email]
    mailto:[hidden email]

<*> To unsubscribe from this group, send an email to:
    [hidden email]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/

12