Thursday, October 19, 2006

Asynchronicity Blues - managing multiple dataservice calls

A while ago I once again came up face to face with the mean and hungry asynchronicity beast that lives within Flex. All I was trying to do was create and save a Contact record programmaticly. The problem was, however, that a Contact has references to ContactType, Country and Division. Simplified, I was trying do the following:

countryService.fill(countries);
contactTypeService.fill(contactTypes);
divisionService.fill(divisions);
contact.country = countries.getItemAt(0); //default
contact.contactType = contactTypes.getItemAt(0); //default
contact.division = divisions.getItemAt(0); //default
contactService.createItem(contact);

Of course, most of the time this would fail because the collections would not yet be filled, being asynchronous in nature. So I had to find a workaround. I created a dataTasks collection and then added a dataTask prior to each fill to the collection. On the result event of each fill I would find my dataTask and remove it from the collection. I added an EventListener to the CHANGE event of my dataTasks collection and when the collection length was back to 0, I would remove the EventListener and create my Contact. This worked fine, however it required alot more coding. Here's what it looked like:
//prior to fill
if(contactTypes.length == 0){
dataTask = new DataTask("ContactTypes",false);
model.dataTasks.addItem(dataTask);}
contactTypeService.fill(contactTypes, "flex:hql", "from ContactType");
//onResult Event
if(dataTask){
model.dataTasks.removeItemAt(model.dataTasks.getItemIndex(dataTask));
dataTask = null;}
//add Eventlistener to dataTasks
model.dataTasks.addEventListener(CollectionEvent.COLLECTION_CHANGE,completeContact);
...
private function completeContact(evt:CollectionEvent = null):void{
if(model.dataTasks.length == 0) {
model.dataTasks.removeEventListener
(CollectionEvent.COLLECTION_CHANGE,completeContact);
var contact:Contact = new Contact();
...
Again, I posted on Flexcoders as to whether or not this was the BEST way to do this, and again Mr. Vroom responded. He wrote that even though the calls on the client are made ASYNCHRONOUSLY, the server handles the requests in SYNCHRONOUS order. In other words I only have to listen for the result event of the LAST fill called. When that result is returned to the client, barring any faults from the previous fills, we can assume that all collections have been filled. Yay! Less Code!

1 comment:

ckeromen said...

I'm facing equivalent problems.
I don't understand why server answers are supposed to be synchronous ??
The time needed for processing each requests may vary and the response for request 2 may arrive after response for request 4 ?