I've been doing some AJAX work (a large tree viewer) using the wonderful DWR.
One thing I see missing from most of the discussions about AJAX is implicit in its name: the calls are Asynchronous. This introduces
the potential for some very nasty bugs when the state of the view is different to the state when the remote method was called.
If (as is typically the case), the data returned from the call is used to modify the view all kinds of unusual problems ensure.
(Here comes my “doh!” confession…)
onClick handler then made a call via DWR to the server to get data, and the function that was called when the data is returned added
the data as tree nodes under the current node.
In 99% of cases this worked fine, until I suddenly discovered nodes appearing under the
wrong parent. What had happened was that the server was under more load, there were more nodes in one particular branch and the data was taking
longer to return than before. That gave me a chance to click on a different node (changing the currentNode variable), and when the data
was returned it was added under the new currentNode.
Now (of course) that bug seems obvious, but I've never seen much discussion of this previously, so I suspect I'm not the only one who
has been bitten by it.
There are two solutions I know to this problem:
- Lock the view. This means having a flag variable that makes sure only one call is in progress at any time. It has the
advantage of being very easy to code and debug, but the disadvantage of restricting the number of things that occur at once.
- Pass the view state to the remote method and return it along with the data. This means the the function that processes the
returned data can reconstruct the correct view state when the data is available. This has the advantage of allowing multiple interactions
to occur at the same time on the same screen, but makes coding much more difficult (for instance, is it always appropriate to reconstruct
the old view state when the user has chosen to do something else?)
In my case I just locked the view. That appears to have worked well, but I am tempted by the potential of the alternative method. I'd really like
to see some kind of toolkit support for this kind of thing.