While developing a mobile PhoneGap app I had an interesting problem. I needed to query about 10 items of data from the database (through PhoneGaps SQLite API)… Like many javascript API’s, this one was asynchronous. When you made your query, you would pass in a “success” handler.
Now, my preference in this case would have been a synchronous query method that returned only when complete. Then I could have written straight line code that queried each of the 10 items 1 after another.
Because of the asynchronous nature of PhoneGap (really, I see this all over JS however) I was forced to write a beast that looked like this:
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
db.query( "SELECT...", success() {
}
}
}
}
}
And this is only half as deep as I had to go (and greatly simplified…)… When, had I been using SQLite in C, I could have simply done something like:
db.query( "SELECT...", resultA );
db.query( "SELECT...", resultB );
db.query( "SELECT...", resultC );
db.query( "SELECT...", resultD );
db.query( "SELECT...", resultE );
It seems to me that the success handler approach is great when you only have to go 1 or 2 levels deep… But, completely falls apart when you need more than that…
Is their a library, or feature of a library somewhere that makes this easier?
This is a problem that is so prevalent in the community that many patterns and libraries have arisen to combat it.
My favorite is promises. I gave a presentation on promises as a solution to the async problem at a few events; you can check out my slides on SlideShare: Callbacks, Promises, and Coroutines (oh my!): The Evolution of Asynchronicity in JavaScript. It also explains why asynchronicity is necessary—in short, because JavaScript is single-threaded.
For the particular example you give, check out slide 53 and thereabouts. In brief, assuming
db.queryreturned a promise, it would look like:Of course it becomes a lot nicer if you don’t need to use the results of one query for the next: