SQLite查询中的javascript for循环

时间:2012-03-26 11:32:06

标签: javascript sqlite

我创建了一个函数,它将从我的数据库返回字符串“path”。

    function getAudio(mid, cb) {
    //mid is an array containing the id to some multimedia files.
    for(i=0; i < mid.length; i++) {

        db.transaction(function(tx) {
                tx.executeSql('SELECT * FROM Multimedia WHERE Mid=' + mid[i] + ' AND Type=' + 2, [], function(tx, results) {    
                //type=2 is audio. (type=1 is picture file etc) There is only one audiofile in the array.
                    if(results.rows.length > 0) {
                        path = results.rows.item(0).Path; 
                        cb(path);
                    }
                }, errorCB);
        }, errorCBQuery);

    }//end for
}//end getAudio()

当我删除for循环时,查询成功,当for循环存在时, 调用errorCBQuery或errorCB。

有关如何解决此问题的任何想法?谢谢:))

1 个答案:

答案 0 :(得分:6)

这是经典的闭包问题。 transaction是一个异步调用,这意味着您的循环在您传入的函数被触发之前完成。该函数对i变量有持久引用,而不是您调用transaction时的副本。所以这些函数中的每一个(你在每个循环上生成一个)都会看到i == mid.length,因此mid[i]undefined,你的SQL就搞砸了。

您需要做的是让回调关闭另一个变量,该变量在循环进行时不会改变。通常的方法是使用工厂函数:

function getAudio(mid, cb) {
    //mid is an array containing the id to some multimedia files.
    for(i=0; i < mid.length; i++) {

        db.transaction(makeTx(mid[i]), errorCBQuery);

    }//end for

    function makeTx(val) {
        return function(tx) {
            tx.executeSql('SELECT * FROM Multimedia WHERE Mid=' + val + ' AND Type=' + 2, [], function(tx, results) {    
            //type=2 is audio. (type=1 is picture file etc) There is only one audiofile in the array.
                if(results.rows.length > 0) {
                    path = results.rows.item(0).Path; 
                    cb(path);
                }
            }, errorCB);
        };
    }

}//end getAudio()

在那里,我将mid[i]传递给makeTx函数,返回将传递给transaction的函数。我们返回的函数关闭了创建它的val调用的makeTx参数,该参数不会改变。

这是代码的 minimal 重写;你可以更进一步。例如,请参阅missingno对问题参数化语句的评论。


旁注:您似乎无法在任何地方声明ipath。如果这是真的,你就会成为 The Horror of Implicit Globals 的牺牲品。建议宣布它们。