January 2015

Gavin Pickin

Pre-mature Optimization - Pre-mature Blog - Gotcha WebSQL Open Database

Javascript, Techie Gotchas, WebSQL

I have written a few posts so far about WebSQL, why I like it, especially in this cross platform Cordova / Phonegap App development world, and a getting started post, where I was wrong. Yes, I Pre-maturely posted that Blog, so this is me fixing it, of course, I edited the original post right away, but here, I’ll go into what I stated wrong, and how it took me way too long to figure out I was wrong, and how sometimes Pre-mature Optimization isn’t needed, but sometimes, it will help show you how wrong you were.

I incorrectly stated that the openDatabase call took 4 arguments + 2 callbacks, 6 total arguments. The openDatabase call actually takes 5 total arguments, the 5th being a callback. I had assumed there was a onSuccess callback, and onError callback, but there was only one callback. I looked through some of my history, and I believe I just ASSUMED those two callbacks existed, since most examples don’t use a callback, and all the other callbacks in the API have onSuccess and onError, so I must have merged them. I think the process I went through, although painful at the time, was pretty interesting, and is worth writing, therefore, worth reading, so I’ll tell you my story.

Assuming since most of the WebSQL API is async*, I wrapped my openDatabase call in a deferred / promise. 
Note there is a way to force sync but it seems counter productive these days to force it to be blocking, especially with UI like an App etc.

I wrapped the call, and it looked something like this.

I ran my app, the “done” wasn’t firing. I added a series of console logs, here, there and everywhere. It looked like I had something wrong with my promise, maybe I wasn’t returning the deferred correctly. I racked my brain for a long time. Eventually, I thought maybe I was erring in the openDatabase call itself, but if I removed it from the promise it worked. Frustrated, I ended up changing a lot of code, and eventually, it fired… but not again after that.

I tried to get the openDatabase call to fail, but my promise never failed and resolved with a reject… so then I realized, these callbacks are not behaving at all like I thought, I better check the documentation. 
There is no 6th argument, an onError callback, so of course my promise would never respond with d.reject(error) because there are no such callback. There is a 5th argument, a callback, but its not on success, its on Creation. So it only ever fires, when the DB is created. If it exists, it never fires.

So it seemed that I was wrapping this Async function in a Promise, that I couldn’t resolve. I wondered, maybe I can find another way to see that the Async has completed, and then resolve the deferred… again this was not easy. So I decided to test the openDatabase, and see if I could just check the object and maybe use a timeout to check for the resulting object.

I logged before the openDatabase call, and immediately after it, and I realized, that the API might be Async, the creation might be Async, but the call immediately returns a decorated object, and no matter what I did, I always had that object… so it seems that the API itself handles the async issue with the db internally. Even if the DB was not present, and had to be created, the DB object returned would be returned instantly, all the functions would be present, I can call them, and under the covers, if you call a query too soon, it waits until it is ready, and then calls it.

I could not break it, which is great design on their side, but it taught me 2 lessons, well at least 2 lessons:

  • RTFM - Read the FREAKING Manual (or something more vulgar)
  • Do not try to pre-maturely optimize - I was optimizing for a case that could never exist, probably more RTFM
  • Be careful not to blog too quickly, because sometimes you’re 1 chapter behind the teacher, and you’ll make a fool of yourself :)

Anyways, I thought it was an interesting story… long story short, openDatabase call is super quick and doesn’t need a Promise wrapper, but you can tell if the DB is being created with that callback… if you want to error catch it, you’ll have to Try Catch it.

Thanks for reading, now I need to finish that article on wrapping the WebSQL API calls using Promises.

Blog Search