converting an asynchronous api to synchronous one. (I have a good reason I promise)

1.1k Views Asked by At

So we have an existing, fairly large, application that is using a synchronous javascript API. In this case Google Gears SQL. We are trying to demo for our clients that it is possible to get the app to work on platforms that don't support gears (in this case iOS) and if they like what they see we will redo the whole app the right way using HTML5 localStorage but for now we need to get it working, even if poorly, using Web SQL. The problem of course is that Web SQL is asynchronous and Gears SQL is synchronous. We already have an abstraction we are using to talk to gears so if we want to change that abstraction to talk to web SQL instead. I tried using an approach like this one: http://jsfiddle.net/ZCD4u/ to fake the synchronous behavior but the Web SQL query never executed while it was blocked. I also tried putting all of the db stuff in a web worker thinking that it would block in the page but execute the SQL anyway. The problem is that the listener that is waiting to hear back from the worker is never fired while my sleep loop is still blocking. What I need is a way to modify an abstraction that uses a synchronous api so that it instead uses an asynchronous api without changing the api of my own abstraction. That is to say that if when I'm done with the abstraction it exposes a callback mechanism to the rest of the app then I have failed. More concretely:

File that I am not allowed to change:

var sql = 'SELECT things FROM tables';
var res = myCoolAbstraction(sql);
dothings(res);

File that I need to change so that it can use Web SQL instead of Gears:

var myCoolAbstraction = function(sql) {
    return doGearsThing(sql);
};

Solution that doesn't work because sleep isn't a real thing in Javascript:

var myCoolAbstraction = function(sql) {
    var res;
    doWebSQLThing(sql, function(d) {
        res = d;
    });
    while (res === undefined) {
        sleep(100);
    }
    return res
};

Any solution that changes the behavior or content of the code in the first code block above fails.

Edit: I suspect this cannot be done and we are looking into other options for this demo but I would love to know if somebody has a solution.

1

There are 1 best solutions below

1
On

WebSQL is async API. It is not possible to convert async function to sync function since it rely on run-to-completion execution model. It means that callback function will invoke only after currently execution stack is completed.

However there is generator in new ecmascript standard, which allow suspended execution contexts. Execution is pause on each yield statement. You can use that feature to write linear workflow while database request are in async, as follow:

var db = new ydn.db.Storage(db_name, schema);
db.spawn(function* (tdb) {
  var value_1 = yield tdb.get('st', key_1);
  value_1.amount += 10;
  var key_1 = yield tdb.put('st', value_1);
  var value = yield tdb.get('st', key_1);
  console.log(value);
};, ['st'], 'readwrite'));

You can test this unit test on Firefox nightly and Chrome with harmony flag on.