Unfucking the ExternalInterface (1 of 2)
May 4th, 2008
or – Asynchronous Communication and the AS3 ExternalInterface
I just deleted four paragraphs of this post, since they could be summed up as “I hate ExternalInterface because it's slow,” which isn’t even an accurate grievance. ExternalInterface is pretty quick. It's the function’s being called by it that are slow.
My real frustration is that communication between Flash and JS is synchronous. That is, whenever Flash calls out to run a javascript function, all action inside Flash halts until the JS function is completed. This makes sense if you’re using getters and setters, but try anything bigger than that and you’ll start to see problems. At the very shallowest level, you’ll see your animation stutter every time you call out to a JS function that takes more than a couple milliseconds, at deeper levels you’ll enjoy long unexplained freezes and dropped calls.
Before the good stuff, a couple caveats: I’m not a JavaScript guy. I rely on two devs who work wonders with JS – whereas I curl up and stop functioning, the second I lose strict data-typing and custom classes. A lot of the credit for this method goes to them.
Second, the point of this workaround is to decouple AS and JS and let them run at the same time. Doing this sacrifices the return value you get if you wait for a function to complete before jumping back to the other side of the EI.
Step 1. Fix the outbound calls.
The good news first: JS is multithreaded. So if we can get our JS function to run in a different thread than the one targeted by Flash, we can get back to running ActionScript while JS worries about the real work. The secret (thanks to my JS guys!) is JavaScript's setTimeout() function. Here's how it works:
Normally to call a JS function you'd write something like this:
All we need to do is manually construct our JS function signature, and use that as setTimeout’s target:
What does this accomplish? In the first example Flash stops running until foo runs its course. In the second example, Flash is waiting on setTimeout to complete instead. JavaScript will automatically call foo in another thread and return control to Flash, which allows AS to start running again while the foo function can run slowly on the JS side without gumming things up. To see this in action try calling a large empty loop or an alert in JS while you've got some animation going inside Flash.
Next post: Inbound calls, custom events, and data validation, oh my!
continued: Unfucking the ExternalInterface (2 of 2) ⇢

August 26th, 2008 at 8:30 am
[...] I found a way around this by wrapping all the callbacks from Flash in a setTimeout method. This effectively opens a new javascript thread and as such straight away returns the original callback. I picked up this tip here. [...]
January 8th, 2009 at 10:02 am
Good job! Saved me a bunch of time.
September 13th, 2009 at 5:52 am
The Method works ok for functions with a predefined set of arguments. But if you somehow have a user-generated String as Argument, problems occurr if the string contains quotes or newline characters, etc.
Javascript will throw an error like “unterminated string literal…”
i wonder how we can fix this.
September 13th, 2009 at 6:28 am
Good point quirx – although that’s more of a limitation of the ExternalInterface in general. Try calling escape() on your strings in JS, and unescape() when you receive the param in AS.
September 28th, 2009 at 3:15 pm
Has anyone had any issues with subsequent ExternalInterface calls? I’m using a time out method as mentioned here to make an ExternalInterface call, but it seems that any subsequent ExternalInterface call simply doesn’t occur. Oddly, it seems that every other ExternalInterface call is successful. Is there a way to ‘flush’ the ExternalInterface?
December 23rd, 2009 at 11:00 am
I kept getting a foo is not defined error and changed the JS_CALL const to:
const JS_CALL:String = JS_FUNCTION + ‘(“‘ + ARG + ‘”)’;
and that fixed it
December 23rd, 2009 at 11:33 am
Nice catch Ronnie, fixed it in the post.
April 3rd, 2010 at 1:03 pm
[...] mistake is assuming the behavior of the string replace method will impact all possible matches. …Calypso88 Blog Archive Unfucking the ExternalInterface (1 …… generated String as Argument, problems occurr if the string contains … const JS_CALL:String = [...]