Well, I wouldn't use the term "horrible", but yeah, what you're doing
isn't optimal.  Let me try to illustrate:

 

A bunch of xml nodes come over the wire.  Your resultFormat is "object"
so the service is going to do:

 

for (i= 0; i < numNodes; i++)

            <convert to object>

 

Then dispatch the result event.  Your code then checks to see if there
are old rows so let's say there are.  Your code will do:

 

For (i = 0; i < numOldRows; i++)

            <delete old row>

 

Then

 

For (I = 0; I < numNodes; i++)

{

            <make an object>

            <add to collection>

}

 

That means that: 1) you've converted to object twice and 2) you've
scanned your data set three times if there were old nodes to remove.

 

And, to make matters worse, calling addItem and removeItem on a
collection is expensive as it must send notifications to everybody who
cares that the collection changed so really the last loop is:

 

for (I = 0; I < numNodes; i++)

{

            <make an object>

            <add to collection>

            <collection prepares a change notification>

}

 

 

And I can't tell from what you sent, but it appears,you might be setting
the dataprovider on the datagrid inside the loop?  If you did that, the
last loop is really:

 

for (I = 0; I < numNodes; i++)

{

            <make an object>

            <add to collection>

            <collection prepares and sends a change notification>

            <datagrid handles change by checking seleted index and
scrollbars and more

            <datagrid gets a new dataprovider>

            <datagrid processes getting a new dataprovider>

}

 

As you can see, that's a lot of loops doing a lot of work.  BTW, I'm not
trying to make you look bad here, plenty of others make these kinds of
mistakes so I'm just using your example to hopefully help many more
folks than just you. 

 

So, how can this be done better?

 

You could just use resultFormat="e4x".  It consumes a lot of memory, but
if you only get one or two queries it may not be fatal.  It depends on
your target scenarios.  Scott has 1000's of rows fetched many times so
it was definitely fatal for him.  The e4x can go straight into the
datagrid without transformation and thus avoiding essentially all of
these loops, but property access to XML is slower so there's a trade-off
there.

 

I would definitely try to avoid cleaning up the old rows.  Properly
designed, you should just be able to abandon the old array of rows w/o
leaking memory as nothing should continue to reference them.

 

If you do convert to object, I would build up an intermediate array of
objects and then assign it as the .source of the array collection.  When
you replace the source in an array collection it should properly abandon
the old array of rows.

 

Finally, I would consider sticking with resultFormat="e4x" and
converting to the right objects once in the result handler.  I've got a
side project going now where I'm pretty much going to do that, although
I'm going to play with an on-the-fly XML to object conversion which I
think will be truly optimal as it won't take time to convert xml nodes
that never get displayed in the datagrid.

 

And, FWIW, I'm still concerned about your combobox renderers.  They can
also be slow to create and initialize and personally, I'm not fond of
the visuals of a stack of them.  You can use a ComboBox itemEditor to
allow the user to choose only for the cell currently being edited but
have the plain text be easier on the eyes for the other cells.

 

HTH,

-Alex

 

________________________________

From: [email protected] [mailto:[EMAIL PROTECTED] On
Behalf Of j_lentzz
Sent: Saturday, September 29, 2007 5:26 AM
To: [email protected]
Subject: [flexcoders] Re: HTTPService Performance Issue - very slow

 

Here are some snippets to show how I'm accessing using the resulting
data - Is this a really slow way to do it? (I've removed some of the
error checking to keep it shorter)

This is how I point to the data when it returns:

private var servletScreenData:Object;
private var servletAddEditScreen_LPA_rowsAddedData:Object; // Row data
for embedded rows in widget

private function handleGetScreenDataResult(event:ResultEvent):void {
if (event.result.getResponse.addEditScreen != null) {
servletScreenData = event.result.getResponse.addEditScreen;
if (event.result.getResponse.addEditScreen.LPA_rowsAdded.row !=null)

servletAddEditScreen_LPA_rowsAddedData =
event.result.getResponse.addEditScreen.LPA_rowsAdded.row; // Row data
for embedded rows in widget

I then store it to the parent level fields like this:
if (servletScreenData != null) {
if (servletScreenData.title != null)
addEditScreenTitle.text = servletScreenData.title;
if (servletScreenData.appName != null)
appName.dropDownValue= servletScreenData.appName;
and so on....

For the datagrid, I apply it like this:

// clear out existing data in LPA
LPA_rowsAdded.list=null;
if (servletAddEditScreen_LPA_rowsAddedData != null) {
if (servletAddEditScreen_LPA_rowsAddedData.length > 0) {
for (var j1:int=0; j1<servletAddEditScreen_LPA_rowsAddedData.length;
j1++) {
obj = new Object();
if (servletAddEditScreen_LPA_rowsAddedData[j1] != null) {
if (servletAddEditScreen_LPA_rowsAddedData[j1].rowdefID != null)
obj.rowdefID = servletAddEditScreen_LPA_rowsAddedData[j1].rowdefID;
if (servletAddEditScreen_LPA_rowsAddedData[j1].fieldName != null)
obj.fieldName = servletAddEditScreen_LPA_rowsAddedData[j1].fieldName;

and so on to completely fill an object containing the datagrid's row
of data: I then use:

LPA_rowsAdded.addListItem(obj);

To add the row of data to the datagrids backing arrayCollection.

The routine does a little processing to see what type of data it is to
set some defaults, but then it just call:

_listData.addItem(value);
followed by:
dg.dataProvider = _listData;
dg.rowCount = ROWCOUNTOFFSET + _listData.length;

to add to the arrayCollection.

These lines of code are in the loop, so I execute them for each row in
the datagrid.

Am I just doing something horribly inefficient?

Thanks for any input.

John
--- In [email protected] <mailto:flexcoders%40yahoogroups.com>
, "Alex Harui" <[EMAIL PROTECTED]> wrote:
>
> If your resultFormat is Object, I'm pretty sure all of the XML has to
be
> parsed into objects before the busy cursor goes away and the result
> handler fires. I would expect noticeably faster response if the
> resultFormat is e4x.
> 
> 
> 
> But as Scott has found out, memory utilization of XML collections is
> much higher than objects in ArrayCollection. I spent a week studying
> the issue and we've made some improvements in Moxie, but it XML will
> always take more memory and fetching properties out of XML is
measurably
> slower than fetching properties out of objects. Thus, you have to
> trade-off how much XML data you're getting, the time to convert it to
> objects and the time you'd spend accessing it if you didn't convert
it.
> 
> 
> 
> I don't know if anyone has created a background task that will convert
> XML to objects, but I've been thinking about doing that one of these
> days. That would allow you to show more than a busy cursor, but will
> delay the total time until you see the data in the views, so there
will
> be another trade-off. Another twist would be a custom collection that
> converts the XML to objects as they are fetched from the collection.
> 
> 
> 
> You should see the busy cursor "freeze" the moment it tries to do the
> xml conversion to object. Then it should go away and there will be
> another pause while the DG builds the renderers. If you've got lots of
> comboboxes, you'll definitely feel it. A quick way to compare it to
> sub-out the comboboxes for the default renderer and see if you can
tell
> the difference.
> 
> 
> 
> I'll put in trace statements and call getTimer() in "enterFrame"
events
> as way to measure where your time is going. The Moxie beta due out
next
> week has some profiling capability that will help you too, but
> optimizing DG performance will have the biggest payoff.
> 
> 
> 
> ________________________________
> 
> From: [email protected] <mailto:flexcoders%40yahoogroups.com>
[mailto:[email protected] <mailto:flexcoders%40yahoogroups.com>
] On
> Behalf Of j_lentzz
> Sent: Friday, September 28, 2007 6:54 PM
> To: [email protected] <mailto:flexcoders%40yahoogroups.com> 
> Subject: [flexcoders] Re: HTTPService Performance Issue - very slow
> 
> 
> 
> Yes, I am using a result handler. The timers I've used have timed
> from when the result handler gets called until the time I finish
> processing all the data and then let the Flex stuff do its thing. 
> This time is very small and I can't start timing any sooner than the
> result handler. I'm sure using extended components vs the heavy
> combobox would help, but I'm confused about why the busy cursor is
> staying on so long. Once it goes away, the complete screen draws
> nearly instantly. Is there anything to be done to speed the
> processing of the incoming data until the result handler is called?
> 
> Thanks a bunch,
> 
> John
> 
> --- In [email protected]
<mailto:flexcoders%40yahoogroups.com>
<mailto:flexcoders%40yahoogroups.com>
> , Scott - FastLane <smelby@> wrote:
> >
> > oops... sorry about the prior message. Doh!
> > 
> > It has also been my experience that rendering is usually the 
> > bottleneck. See this post on my blog
> <http://blog.fastlanesw.com/?p=25 <http://blog.fastlanesw.com/?p=25>
<http://blog.fastlanesw.com/?p=25 <http://blog.fastlanesw.com/?p=25> > >

> > for an example of the difference a UIComponent based renderer can
make
> 
> > over containers.
> > 
> > hth
> > Scott
> > 
> > Tracy Spratt wrote:
> > >
> > > In my experience, the rendering of the UI is the bottleneck, not
the
> 
> > > data transfer.
> > >
> > > 
> > >
> > > Use timer and the result handler function to time the actual data 
> > > transfer. You ARE using a result handler, and not binding
> directly to 
> > > lastResult, right?
> > >
> > > 
> > >
> > > Are your item renderers built on containers? If so, you need to
move
> 
> > > to extending UIComponent instead. See Alex Harui's blog for a full

> > > explanation why, and for many examples.
> > >
> > > 
> > >
> > > Tracy
> > >
> > > 
> > >
> > >
> ----------------------------------------------------------
> > >
> > > *From:* [email protected]
<mailto:flexcoders%40yahoogroups.com> 
> <mailto:flexcoders%40yahoogroups.com> 
> [mailto:[email protected]
<mailto:flexcoders%40yahoogroups.com>
<mailto:flexcoders%40yahoogroups.com>
> ] 
> > > *On Behalf Of *j_lentzz
> > > *Sent:* Friday, September 28, 2007 2:11 PM
> > > *To:* [email protected]
<mailto:flexcoders%40yahoogroups.com> 
> <mailto:flexcoders%40yahoogroups.com> 
> > > *Subject:* [flexcoders] HTTPService Performance Issue - very slow
> > >
> > > 
> > >
> > > Hi,
> > >
> > > I've got an app getting data from a server to populate a screen
with
> > > 3, text inputs, some radio buttons and a data grid. With some
data,
> > > it is taking almost a minute to save and refresh the scren. The
data
> > > grid seems to be the issue. It contains many comboboxes. I've read
> > > that these are very slow if too many appear in a datagrid. I see
the
> > > last data leave the server and I have timer marks for when I start
> my
> > > processing of the returned data (populating the arraycollection
for
> > > the datagrid - I'm using the default resultFormat of Object) to
when
> > > I'm done and just waiting on the screen to display it. The
> processing
> > > time I'm getting from the timers is very low (1/2 sec or less).
> > > However, I'm seeing the busy cursor staying on the screen for
almost
> > > the complete time I'm waiting. Once the busy cursor leaves, the
> > > screen appears almost instantly with data. The docs say that the
> busy
> > > cursor is displayed until the class completes loading data. So is
> the
> > > bottleneck on the Flex side (the loading of the data from the
> > > HTTPService) that I can't access? Or is my datagrid full of
> > > comboboxes the issue, even though the busy cursor is staying on
the
> > > screen.
> > >
> > > Any guidance would be appreciated.
> > >
> > > Thanks,
> > >
> > > John
> > >
> > >
> >
>

 

Reply via email to