I was curious as to the difference between a few different ways of
approaching the situation of an itemRenderer having a "data" property and
deciding whether or not to use "as" to make all the type checking happy.  So
I tried some test code and found that it made a big difference whether you
use "as" or just leave the data property as an Object.  If you leave it as
an Object, you get a performance hit on the order of 40%+ longer than if you
use "as" to cast it first.

Here are the ways I tested it.  I just decided to pull the "id" property
because it's something that is just a simple access of a private variable,
no complicated stuff.

var b:Button = new Button;
var o:Object = b;
var s:String;

s = b.id;
s = (o as Button).id;
s = Button(o).id;
s = UIComponent(o).id;
s = (o as UIComponent).id;
s = o.id;

I did get a bit fancy and put them in a loop and a timer to isolate each
one.  The full code is included below.

What I found was along the lines of this (give or take a few %):

Button:         3.16
Button():       4.06      129%
as Button:      4.14      131%
UIComponent():  3.98      126%
as UIComponent: 4.03      128%
Object:         5.38      170%

I put in the UIComponent ones because sometimes I cast it to a superclass
because I might get several different subclasses passed into a function.

So what I've found is that if you ignore than noise, the middle four methods
are also approximately the same in timings.  But the Object one is far
worse.  This probably won't come as any surprise to the Adobe folks or the
people who have been working with Flex a bit more in-depth.  I found it
rather useful information, though, considering I'm trying to shave off some
time in various places in one of my apps.  Granted, it won't matter as much
outside of loops.

So many things return the items as objects, such as Arrays/ArrayCollection,
the "data" property of item renderers, etc.  I think I'm just going to make
it a habit to put "as" in my code (and not the format of Class(variable)
because sometimes that triggers a function rather than just doing a casting)
all the time.  It helps catch errors by doing strict type checking (as long
as you aren't using dynamic classes) and it's a little faster to boot.

Still, I wish it was as fast as the top line where you don't have to do any
casting/as at all.  Any thoughts on that or anything else I've missed?  Any
flash insiders want to give your insight on why it works this way under the
hood?


<?xml version="1.0" encoding="utf-8"?>
<Application
  xmlns="http://www.adobe.com/2006/mxml";
  >
  <Script>
    <![CDATA[
      import mx.core.UIComponent;

      private var timer:Timer = new Timer(100);
      private var mode:int = 0;

      private function doClick(e:Event):void
      {
        if (timer.running)
        {
          timer.stop();
          timer.removeEventListener(TimerEvent.TIMER, timerClick);
        }
        else
        {
          timer.addEventListener(TimerEvent.TIMER, timerClick);
          timer.start();
        }
      }

      private var last:Number;
      private var b:Button = new Button;
      private var o:Object = b;
      private var s:String;
      private var i:int;
      private var traceStart:Date;
      private var loops:int = 10000000;
      private var time:Number;

      private function timerClick(e:Event):void
      {
        timer.stop();

        switch(mode)
        {
          case 0:
            trace();

            traceStart = new Date();
            for (i = 0; i < loops; i++)
              s = b.id;
            time = (new Date().time - traceStart.time);
            trace("Button:\t\t", (time / 1000).toFixed(2));
            last = time;
            break;

          case 1:
            traceStart = new Date();
            for (i = 0; i < loops; i++)
              s = (o as Button).id;
            time = (new Date().time - traceStart.time);
            trace("as Button:\t",
                (time / 1000).toFixed(2), "\t", ((time / last) *
100).toFixed(0) + "%");
            break;

          case 2:
            traceStart = new Date();
            for (i = 0; i < loops; i++)
              s = Button(o).id;
            time = (new Date().time - traceStart.time);
            trace("Button():\t",
                (time / 1000).toFixed(2), "\t", ((time / last) *
100).toFixed(0) + "%");
            break;

          case 3:
            traceStart = new Date();
            for (i = 0; i < loops; i++)
              s = (o as UIComponent).id;
            time = (new Date().time - traceStart.time);
            trace("as UIComponent:\t",
                (time / 1000).toFixed(2), "\t", ((time / last) *
100).toFixed(0) + "%");
            break;

          case 4:
            traceStart = new Date();
            for (i = 0; i < loops; i++)
              s = UIComponent(o).id;
            time = (new Date().time - traceStart.time);
            trace("UIComponent():\t",
                (time / 1000).toFixed(2), "\t", ((time / last) *
100).toFixed(0) + "%");
            break;

          case 5:
            traceStart = new Date();
            for (i = 0; i < loops; i++)
              s = o.id;
            time = (new Date().time - traceStart.time);
            trace("Object:\t\t",
                (time / 1000).toFixed(2), "\t", ((time / last) *
100).toFixed(0) + "%");
            break;
        }

        mode = (mode + 1) % 6;

        timer.start();
      }
    ]]>
  </Script>
  <Button click="doClick(event)"/>
</Application>


-- 
Jason

Reply via email to