Make function call wait for web SQL query

harryfonda picture harryfonda · Sep 17, 2012 · Viewed 7.6k times · Source

Primecheck function is supposed to return true or false whether passed number is prime or not. If the number is prime, function adds it to PRIMES table. This is a Sieve of Eratosthenes algorithm, but it's not finished yet.

function primecheck (number) {
    var isprime = true;
        if (number%10 == 1 || number%10 == 3 || number%10 == 7 || number%10 == 9) {
        db.transaction(function (tx) {
            tx.executeSql('SELECT * from Primes', [], function (tx, result) {
                for (var i = 1; i < result.rows.length; i++) {
                    if (number%result.rows.item(i)['prime'] == 0) {
                        isprime = false;
                        break;
                    }
                }
                if (isprime) {
                    tx.executeSql('INSERT INTO PRIMES (prime) values (?)', [number]);
                }
                return isprime;
            }, null);
        }, null, null);

    }
    else {
        isprime = false;
        return isprime;
    }
}

Problem: when I pass numbers that do not end on 1, 3, 7, 9, function returns true, it's ok. But when I pass other numbers, function returns undefined. I suppose it's because function call doesn't "wait" for SQL query to finish, so I must use some kind of callback functions. But it didn't work.

Answer

apsillers picture apsillers · Sep 17, 2012

If your function performs asynchronous operations, it cannot return a value based on the result of those asynchronous operations. (This is because the asynchronous functions won't run until the current execution is finished, due to the single-threaded nature of JavaScript.) Instead, your function should expect a callback function that takes the would-be return value as an argument.

You currently call your function like:

var isprime = primecheck(someNum);
// now do something with isprime

But you need to use a callback:

primecheck(someNum, function(isprime) {
    // now do something with isprime
});

Just add a second callback argument, and call that callback instead of using a return:

function primecheck (number, callback) {
    var isprime = true;
        if (number%10 == 1 || number%10 == 3 || number%10 == 7 || number%10 == 9) {
        db.transaction(function (tx) {
            tx.executeSql('SELECT * from Primes', [], function (tx, result) {
                //....
                callback(isprime);
            }, null);
        }, null, null);
    }
    else {
        isprime = false;
        callback(isprime);
    }
}

Now, primecheck returns nothing, but the callback function you pass into primecheck will get fired with isprime as its first argument whenever primecheck determines the primality of the input.