Sunday, July 3, 2011

Going Faster by Slowing Down

I made another slight improvement to my AJAX multiplexer, of an amusing sort. I made it go faster (overall) by delaying the first message.

See, it turns out that when some AJAX data is needed to fill in a control field (I'm going a scattered widget-based scheme rather than neat standard single-form blocks) it tends to be requested in 'flurries'. A couple of controls will pop up together, (possibly as a result of another AJAX call) get their acts together, and decide they are hungry for more data.

Previously, the first data operation would immediately kick off an AJAX operation. This blocks other outgoing messages until the call comes back (otherwise we're using multiple connections, and that can cause issues elsewhere) during which time more operations queue up.

Once the first small request came back, the rest would get sent in a big batch.

By merely putting in a timer so that you schedule the AJAX request to happen soon but not immediately (10 milliseconds, in this case) you give all the other widgets enough time to 'jump on the bandwagon', and everybody else gets their data faster.

This has a surprising impact on the feel of many page operations. The update behavior just seems more logical. Even though the exact same amount of data is flowing to and fro, it turns out timing is very important for this, as in comedy and love.

Also, I just invented another mini-language. (Well, I'm copying Javascript, sort of) I was getting sick of iterating through the Java Maps and Lists that I get from parsing JSON, and I was really missing how easy it is to reach into a Javascript structure and pull out random items. Java's strict types are actually a bit of a pain, now that I've spent some time in prototypal script land where everything is infinitely malleable.

And that's just iterating over one level with some pretty easygoing constraints and using my convenient is_blah utility functions copied from PHP. Once you get to three or four levels of structure, the amount of code involved starts gets quite staggering and hard to read.

Wouldn't it be nice to use Javascript-like syntax to just grab nodes out of the JSON structure just like jQuery's selectors grab DOM nodes?

That sure would be nice, I thought. And the more I thought about it the nicer it seemed. So I wrote one.

It's only a few hundred lines long, and it lacks nearly every major feature of note, and in fact all it does is, given a arbitrarily complex JSON structure like [{"a":1,"b":2,"c":[1,2,3]}] and a path selector like "[0].c[2]" it picks out the expected entry from the structure. In this case, "3", the final element.

It's like running a tiny, tiny bit of interpreted Javascript code in compiled Java VM, just to pull out a single variable. I can't tell if it's silly, or pure genius.

This collapses enormous repetitive wodges of code down to tiny constant strings expanded by a library. Whether the code runs faster or much, much slower depends on a lot of factors, and isn't straightforward to guess. Several tricks to pre-cache the tokenization would help out immensely, but that's for when I get time. (No premature optimization here...)

The other thing the selection language does is to provide a kind of error checking that's sadly lacking Javascript. each step of the path is either an object property name (a dot, followed by text like ".name" or ".a") or a numeric array index (a number, enclosed in parenthesis, like "[0]" or "[9]") which forces an expected type , at least between objects and arrays. Normally Javascript can use either syntax to access either object properties or array indexes, but throws random exceptions when your expectations don't match the data.

Totally missing features: it only selects one thing at a time, rather than lists of things which I already want to do. And it doesn't know about the standard escape characters yet, but that's just a limitation on the selector string, not the JSON data. The Jackson library is still taking care of all that, and doing a marvelous job.

Now that I've added this handy little feature to my toolbox (and spent the last hour writing test cases to try to make it break) I'll be better prepared for the future. Maybe it will even justify the time. I live in hope.