Sunday, February 22, 2009

YUI 3 Preview Release 2 - IO

Today I will go over the new IO Utility in the YUI 3 Preview Release 2

"IO is an HTTP utility that enables HTTP requests while maintaining a persistent client UI, for the purpose of data retrieval and content update. IO uses the XMLHttpRequest object for making "same-domain" requests. IO can make "cross-domain" requests, when instructed to do so, using an alternate HTTP transport."


What does this mean really? This means we have a single, consistent, interface to various data sources we may point our UI at. This data may be from our site, or another data provider on a different site. When the data resides on our site IO will use XHR (XMLHttpRequest ) to request the data, standard "AJax". When we are making our request cross-domain, the IO utility will use a flash swf to make the call, along with a crossdomain.xml (to let the flash know which sites it has access to). The crossdomain.xml is fairly important on a https: site as IE will complain to no end that you are trying to access non secure data, or mixing secure with non-secure.  The crossdomain.xml resides in your document root.

So, let's see what the YUI 3 team has given us. The basic example provided at the IO Utility page sets up the use of io-base, defines a completed function, and subscribes to the event. The key here seems to be subscribing to the event :


// Subscribe to event "io:complete", and pass an array
// as an argument to the event handler "complete". Since
// "complete" is global.
// At this point in the transaction lifecycle, success or
// failure is not yet know.
Y.on('io:complete', complete, this, ['lorem', 'ipsum']);

When the Y.io(uri) event "complete" finishes, we want to run "complete" function with "this" as the context of execution, and pass also an array ['lorem', 'ipsum']

This may be quite different and confusing to just about every other Framework out there. But so much better! There are a few posts on nabble where people are asking why the IO isn't "seperate" for each request, and the answer lies above. IO is a presistant connection, and it has a context that it runs in. If you are specifying IO in the global context, then all your requests are going to be in the global context, which is specified by "this".

In other words, Event handlers run in thier own context, so you could have multiple listeners on the io:complete event, but only some would run depending on context:    Therefore, you could register a GlobalEvents object and set that context, just as in the examples and this would run for every IO request. If however, you have objects with different scopes, the global would fire as well as the callbacks in different scopes that are set to listen for io:complete.  

The new IO utility also offers a "queue" which you can start, stop, promote, purge, and set the size. This is a big step in ajax frameworks as most like prototype do not come with these capabilities built in. With a queue you can send transactions and gracefully monitor and manage them with the io events and queue commands.

One way I can see this being very useful is if you had created a queue on page onload to load various items not immediatly visible to the user. But say the user then clicks on one of the items, we can immediatly stop the queue, and promote that request to the top of the queue, and when that completes, continue with the loading of the rest of the items! This is, to say the lease, very useful.

3 comments:

Shade said...

have you considered using flXHR [ http://flxhr.flensed.com/ ] for the flash cross domain Ajax calls?

It exposes an identical API to the native XHR object so it requires no further code changes after dropping it into the page, but allows full cross-domain requests.

There are a number of improvements and reasons why flXHR is a better alternative for cross-domain Ajax calls than just custom flash components developed for that purpose, because of the API standardization and optimization techniques, as well as improved policy checking logic over the native plugin's intrinsics.

jminkler said...

@Shade - Won't all the Flash solutions have the same restrictions based on Flash itself? I'm not sure if I would want to override, or mix and match here, and seems like I would then be doing Flash XHR for non cross-domain calls? Or have I missed some point here. Perhaps you can point me to the advantages of a flash solution beyond the cross-domain issue?

Shade said...

@jminkler-
Those are great questions. Let me quickly address them.

1. The flash plugin does have a baseline of cross-domain policy checking functionality. However, in the development of flXHR, I discovered a loophole of sorts that I consider to be a shortcoming of Adobe's current security model. After attempting to get them to address it for months, I decided finally to address it in my own code so that flXHR would be more secured. Essentially, I had to re-implement their policy checking logic to make it more strict and thus more secure. You can read a lot more about it here: http://www.flensed.com/fresh/2008/08/adobe-flash-player-security-hole/.

2. It's true that flXHR could be used for *all* XHR communication, and I think it performs reasonably well in that role. But the beauty of it being identical in API to the normal native XHR is that you could very easily have logic in there (like you already have) which simply instantiates a flXHR object and substitutes it in only if the call is cross-domain.

But all other communication code would be identical regardless of target domain. That's the great part about flXHR's approach, as it simplifies your other code, and makes it only a small simple change to adapt flXHR into the page. ("set it and forget it")

3. Lastly, to address the benefits of a flash solution as opposed to regular XHR or other cross domain Ajax methods: the flXHR object *does* implement some helpful extensions to the native XHR API, like timeouts and easy re-use (instance pooling). So in that way, it's perhaps a decent alternative to XHR. For cross-domain, I believe it to be the clear winner, because it's (flash based solutions, that is) the only solution which specifically grants the target server full policy control to opt-in.

All the other prevalent methods (iframe proxies, window.name, dynamic-script-tags, etc) can easily be spoofed into thinking they are allowing communication from a trusted source when in fact they are enabling "evil.com" sites. The intrinsics of the flash plugin are not nearly as easily fooled. I'd rather trust a plugin that is installed on 99% of computers worldwide (more ubiquitous than any other plugin, and even more than any single browser itself), rather than trusting the dynamic (hackable) Javascript itself.

------------
But lastly, let me say that I think the biggest benefit to standardizing on something like flXHR is that I believe the API is the important thing to consolidate on, while allowing the "under the covers" details (like flash, or some other solution) to be swapped in and out as browser technology progresses or not.

I think it's a bad idea to continue to keep using all these different objects/API's for various different behaviors, because I think developers will be unable to know all the details they need to know to do this stuff securely.

One API is simpler and more secure to standardize on. I think flXHR is a good "shim" until such a time as a more stable and fully cross-browser standardized API comes along.