Posts Tagged ‘Pitfall’

How Flash Player 10.1 “broke” my banner (and how I fixed it)

Maybe you’re one of the people who upgraded recently to Flash Player 10.1. If so, you probably managed to see my banner doing things that I didn’t intend it to when I created it for Flash Players 9 – 10.0. The flaw was subtle, and one that you wouldn’t ever find simply by watching the animation. So how did I find it?

Let’s go back in time a few months, back when Adobe was still bursting with enthusiasm over the prospect of having Flash Player on Apple’s mobile devices. They worked feverishly to implement many changes to the way the Flash Player behaves to minimize its CPU consumption, and as well to reduce potential strain on the batteries of the new breed of mobile devices. One of these changes was to dynamically change the rate at which code executes when the player is not “in focus” (eg: you have a browser with three tabs open, and the Flash Player is open on one of the non-active tabs).

Here’s Tinic Uro’s blog entry in which he gives a very detailed accounting of the changes. For those who don’t wish to read it all, here’s the section that broke my banner:

Implications for user experience

In Flash Player 10.1 SWFs on hidden tabs are limited resource wise. Whereas they would run at full speed in Flash Player 10.0 and before (note though that we NEVER rendered, we only continued to run ActionScript, audio decoding and video decoding), we now throttle the Flash Player when a SWF instance is not visible. Doing this change was not easy as I had to add many exceptions to avoid breaking old content. Here is a list of some of the new rules:

Visible:

* SWF frame rates are limited and aligned to jiffies, i.e. 60 frames a second. (Note that Flash Playe 10.1 Beta 3 still has an upper limit of 120 which will be changed before the final release)
* timers (AS2 Interval and AS3 Timers) are limited and aligned to jiffies.
* local connections are limited and aligned to jiffies. That means a full round trip from one SWF to another will take at least 33 milliseconds. Some reports we get say it can be up to 40ms.
* video is NOT aligned to jiffies and can play at any frame rate. This increases video playback fidelity.

Invisible:

* SWF frame rate is clocked down to 2 frames/sec. No rendering occurs unless the SWF becomes visible again.
* timers (AS2 Interval and AS3 Timers) are clocked down to 2 a second.
* local connections are clocked down to 2 a second.
* video is decoded (not rendered or displayed) using idle CPU time only.
* For backwards compatibility reasons we override the 2 frames/sec frame rate to 8 frames/sec when audio is playing.

kaourantin.net – ‘Timing it right’

Yes, code execution and frame redraws are now limited to 2FPS when the swf is not in the active window. How did that break anything, you might wonder? The danger lies in the new interplay between the ENTER_FRAME event and the Timer object. Judging by the information above, you’d think that there would be no conflict, as Timers and ENTER_FRAME events both dial down to 2FPS, but that doesn’t seem to be the case.

When I created the banner, I used the following structures to control the various events you see:

  • An ENTER_FRAME listener, on which I update the physics simulation and the flame effects.
  • A Timer that spawns a new statement every 5 seconds, to send it crashing to the ground.

The issue here is that, in spite of what is written in kaourantin.net, what actually happens is that while the ENTER_FRAME events do in fact get ratcheted down to 2FPS, the Timer on the other hand still executes every 5 seconds! This means that if you tab away from the banner for a few minutes and then come back a giant rain of broken letters all fall from the sky at once. Well, that’s not so bad right? Isn’t that just a different kind of apocalypse, after all? It would be, if it weren’t for the other side effects…

  1. Once enough words spawn, the mess at the bottom auto-cleans itself, so returning to the page left an odd jumble of letters floating inexplicably
  2. Leaving it in the background long enough seemed to cause a memory backup in Box2D, such that words eventually simply failed to materialize, throwing errors.
  3. Clicking the “Dismiss All” button to silence all the errors and leaving the banner to run overnight caused a memory leak in Firefox that froze the browser.

What was I to do? Well, the only thing I reasonably could do at that point was to change the banner such that the spawn timer was no longer a literal Timer object, but instead was a fake “timer” that counted up by 33 “fake” milliseconds on every ENTER_FRAME event, so that I could get the same desired effect of a new word being spawned every 5 seconds as I had previously. Why use “fake” milliseconds instead of real ones? Because real milliseconds would put me right back in the situation of spawning a new word every 5 seconds while the simulation runs at 2FPS. So, since this blog is all about ActionScript pitfalls and how to avoid them, here’s the latest one learned from hard experience:

Do not mix two different methods of timekeeping in the same application. Either rely on ENTER_FRAME, or Timer exculsively for all things. Not both.

Maybe I’m the fool for trying to mix different methods of keeping time? Somehow I don’t think so. This definitely seems like one of those instances where perfectly valid and accepted practices of the past have been changed dramatically, potentially stranding people who were simply following accepted practice. Not a first for Adobe.

Has anyone else run into weird backwards-breaking issues regarding Timers, ENTER_FRAME, and other custom time-keeping methods such as the use of getTimer() now that Flash Player 10.1 has changed so drastically?

Tags: , , ,

8 Comments


“I put a function in your function, so you can process while you process!”

Maybe you’ve seen this before:

public function foo():void{
    // a function in a function?
    var onLoad:Function = function(e:Event):void{
        addChild(loader);
    }
    var loader:Loader = new Loader();
    loader.addEventListener(Event.COMPLETE, onLoad);
    loader.load(new URLRequest("someSwf.swf"));
}

It appears that the developer in question has written a function inside of a function. They were at least kind enough to assign it to a variable. They could have created one that is completely anonymous.

So, is there something wrong with this? In ActionScript 3 the answer is it kind of depends.

There are legitimate reasons why a developer might wish to do this, and they involve coding around a weakness in the Event model. The most interesting of these reasons is that this style represents the only way you can get away with early binding of variables. In doing so however, it’s easy to create objects that can never be eligible for garbage collection. Notice in the above example that the developer never removed the listener! In the examples to follow, I will exercise due diligence and remove them explicitly.

As an example, I’ve seen developers write code like this, thinking that the value of count will be “fixed” in the event handler to what it was when the handler was assigned:

private var count:int = 0;
private const MAX_COUNT:int = 10;
 
public function foo():void{
    while(count < MAX_COUNT){
 
        var onLoad:Function = function(e:Event):void{
            // offset the loader's x value by width * the number of images loaded.
            loader.x = loader.width * count;
            addChild(loader);
            e.currentTarget.removeEventListener(Event.COMPLETE, onLoad);
        }
        var loader:Loader = new Loader();
        loader.addEventListener(Event.COMPLETE, onLoad);
        loader.load(new URLRequest("someSwf.swf"));
    }
}

Only to discover that the value contained in count is not at all bound at the time the listener is added. They find that *all* their images end up at content.width * 10. Their next impulse is to “find a way to pass the current count to the event handler”, but you cannot do that. This:

// trying in vain to pass 'count' to the listener...
 loader.addEventListener(Event.COMPLETE, onLoad, count);

Is simply not valid AS3 code. There are two ways around this. My preferred method is to keep your real count at the class level, and to increment it in onLoad rather than to rely on the foo() function, and to never use a nested inner function. This gives the class a very plain set of signatures that can be read and interpreted in a list, and whose namespaces can be changed as needed to allow or deny access from both the outside and the inside. I find it worth the extra few lines of code and scrolling in the short term to have something easier to read in the long term.

 
private var count:int = 0;
private const MAX_COUNT:int = 10;
 
public function foo():void{
    // remove the count from foo, and use a local variable.
    var i:int = 0;
    while(i < MAX_COUNT){
        var loader:Loader = new Loader();
        loader.addEventListener(Event.COMPLETE, onLoad);
        loader.load(new URLRequest("someSwf.swf"));
        i++;
    }
}
private function onLoad(e:Event):void{
    var content:DisplayObject = e.currentTarget.content as DisplayObject;    
    content.x = content.width * count;
    this.addChild(content);    
    // increment the count here.
    count++;
    e.currentTarget.removeEventListener(Event.COMPLETE, onLoad);
}

So as you can see, there’s no need to use the listener-within-a-function. Why then, does it remain tempting for people? Aside from the fact that it requires less scrolling around the page and you can just write out the function in a place where you can see everything you’re thinking about, there is a special way to do this that allows you to use early binding. Get ready, because we’re about to take it another level down the rabbit hole.

public function foo():void{
    // a function in a function?
   for(count ; count < 10 ; count++){
        var onLoadHandler:Function = function():Function{
            var c:int = count;
            // with another function in a function inside of it???
            var handler:Function = function(e:Event):void{
                var count:int = c;
                var displayObject:DisplayObject = e.currentTarget.content as DisplayObject;
                displayObject.x = displayObject.width * count;
                addChild(loader);
 
                // IMPORTANT: Remember to remove your listener!
                e.currentTarget.removeEventListener(Event.COMPLETE, handler);
            }        
            return handler;
        }
        var loader:Loader = new Loader();
        // Call the function onLoadHandler to get the *real* function that is used as the listener as a return value
        loader.addEventListener(Event.COMPLETE, onLoadHandler());
        loader.load(new URLRequest("someSwf.swf"));
    }
 
}

Once you start nesting functions this deeply and returning the inner functions as values to be used, you’re stepping across the line of Object Oriented Programming into Functional Programming, though it’s a half-baby-step in this case. You’ll notice in this instance that the value of “count” in the innermost function is bound to the value of “count” at the class level as it existed when the originating function was declared in the for loop because of the intermediary “c” variable. This works because of the acrobatics involved in working across so many scopes in a single function call. I’ll come out and admit that while it can be initially confusing to see so many functions nested, it *is* convenient not to have to declare extra class level variables or scroll around looking for other functions in the code. You may wonder then why I prefer not to use them.

  • Function calls are processor intensive. Inside a long loop, calling so many functions adds considerable overhead.
  • It obscures your API. These inner-functions and variables never appear on a class diagram.
  • You can not directly touch these functions from anywhere except the scope in which you create them.

1. In my post about Array Optimization you’ll note that there’s nothing particularly intensive happening in those loops. Imagine however, that there *is* something to do in all those locations. There are no empty array locations, and for each item in the array there is a function call. Now imagine that there are two or three function calls. In fact don’t just imagine it, benchmark it yourself. You’ll find that function calls simply consume a great deal more resources than code written inline.

2. It’s one thing to write OOP code with intentional encapsulation such that objects don’t know much about each other. It’s another thing to write it such that the objects don’t know much about themselves. That’s essentially what’s happening when you rely on multiply nested function-scoped functions. It makes the code harder to understand at a glance from a high level. “I know that there’s a function that says to load images, but I don’t see where that’s being handled and I cannot override it in a subclass without overriding the loading function too.

3. This is the really big one, and the one that has the most room to trip you up in weird ways (hence the “pitfall” categorization of this entry). While Flash does offer you the option to add an event listener as a “weak reference” for aid in garbage collection, that doesn’t mean that once the object is eligible for gc that the object has ceased to exist, or that it will stop dispatching events. Far from it! With asynchronous events such as Event.COMPLETE (in the context of loading external content), TimerEvent (all of them), and even the synchronous Event.ENTER_FRAME, you’ll find that these events still dispatch, even if the references are weak, and even if the dispatching object is eligible for garbage collection. How do you remove an event listener that you don’t have any access to outside the scope in which it’s added? The only answer is “you have to do it inside the handler itself” which may not be practical or even possible under many circumstances. It is possible in the context of the Loader class (as demonstrated above) but the waters become murkier with ENTER_FRAME or TimerEvent(s), as the function now needs to undertake the responsibility of checking whether it should somehow remove itself from its dispatcher every time it executes, and possibly aborting execution if it should be removed.. This of course adds CPU overhead to the code, and if the event is dispatched frequently represents a large amount of needless processing.

You’re probably wondering why The Horseman would even tell people that this is possible if he’s so reluctant to use these nested functions himself. The simple answer is that people are going to do this anyway. No matter my own personal preference, there will always be coders whose first inclination is to use functions inside functions, and that’s fine. There’s a whole paradigm based around passing functions and relying ONLY on function scope, in fact! The problem comes when people who don’t know the risks and the trade-offs are careless about using them, particularly in an otherwise Object Oriented environment. Consider this to be a primer on those risks and the trade-offs, at least in the context of ActionScript 3. There are more to consider, but that’s for another time.

Tags: , , , ,

No Comments


trace(fail = true);

I don’t understand it! This section of my code that I haven’t touched in days doesn’t work anymore!

There are a lot of reasons code might suddenly “go bad” for no apparent reason. Generally, it’s related to some unexpected “garbage in -> garbage out” type of situation at runtime, but at times it’s a bit more subtle than that. Attached are two separate flas with identical ActionScript. Both of them compile correctly, and neither throw any runtime errors. One of them exhibits some very strange runtime behavior. See if you can figure out what’s the cause.

What do you suppose could be the issue here?

If you guessed that it has something to do with the trace statements, you’re on the right track.

“But how can the trace statements be the cause of the problem? All they do is write output to the console window.”

Indeed, the trace statement itself does nothing other than print the final expression of its contents to the console window. But have a close look at a couple of the trace statements. Notice anything odd?

trace(m*=Math.PI);
trace(n++);

I frequently hear the phrase “laziness is a virtue” used to describe the qualities of an excellent programmer. Well what could be lazier, and thus closer to perfection than combining our evaluations and our debug output into the same line of code?

Omit trace actions

trace(fail = true);

Oh.

In order to save some filesize, as well as to cut down on the processor load associated with spewing out a lot of trace statements, it appears that the author of the second file has elected to Omit trace actions. What were we doing in those trace statements earlier? Oh, it looks like we were evaluating something. As you can see, if you decide to omit the trace actions (or even just boneheadedly comment them out) you’ll lose some actual logic that you really needed.

Friends don’t let friends evaluate inside trace statements. I’m sure this is equally true in other programming languages.

Tags: , , ,

2 Comments