Запрос Javascript WebSQL внутри цикла for. Как узнать, когда закончите?

Я думаю, у меня есть относительно простой вопрос, но я продолжаю думать по кругу, и даже Google не дает мне ответа, с которым я могу работать.

в основном я пытаюсь скопировать некоторые записи, которые хранятся локально с помощью WebSQL. Копирование не проблема, но мне нужно знать, когда все действия копирования завершены, прежде чем моя программа сможет продолжить.

вызовы WebSQL сделаны asychronous, поэтому единственный способ для меня обычно делать эти вещи-использовать функцию обратного вызова. Однако, поскольку запросы выполняются в цикле for, я не могу использовать функцию обратного вызова, поскольку она будет срабатывать при первом завершенном запросе, как показано в коде.

код выглядит следующим образом:

function copyRecords(old_parent_id, new_parent_id, callback){
    var db = openDatabase('test', '1.0', 'test', 50 * 1024 * 1024);
    db.transaction(function (tx) {
        tx.executeSql('SELECT * FROM table WHERE parent_id = ?', [old_parent_id], function(tx, results){
            for(var i = 0; i < results.rows.length; i++){
                db.transaction(function (tx2) {
                    tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', [results.rows.item(i).name, new_parent_id], callback);
                })
            }
        });
    });
}

Я также попытался вызвать функцию обратного вызова, когда i == results.rows.length, но это не означает, что все запросы завершены.

Я думаю, некоторые из вас столкнулись с той же проблемой раньше, поэтому любая помощь в решении этого и убедитесь, что функция обратного вызова вызывается только тогда, когда цикл for завершен, очень ценится.

спасибо заранее.

2 ответов


обычным подходом для этого было бы использовать рекурсивный асинхронный обратный вызов для обработки каждой отдельной записи вместо for петли.

пока осталось больше записей, асинхронный обратный вызов вызывает сам себя. Если записей не осталось,он может вызвать предоставленный обратный вызов.

приведенный ниже код заменит содержимое вашего внутреннего обработчика обратного вызова:

(function nextRecord() {
    var row = results.rows.shift();
    if (row) {
        db.transaction(function (tx2) {
            tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)',
                [row.item(i).name, new_parent_id], nextRecord);
       });
    } else {
        callback();
    }
})();

это лучше всего сделать, сохраняя количество выполнений функции "обратный вызов", и только после того, как она достигнет полной суммы результирующего набора.

вот ваш код с изменениями:

function copyRecords(old_parent_id, new_parent_id, callback){
    var db = openDatabase('test', '1.0', 'test', 50 * 1024 * 1024);
    db.transaction(function (tx) {
        tx.executeSql('SELECT * FROM table WHERE parent_id = ?', [old_parent_id], function(tx, results){
            if (results.rows.length == 0) 
                callback(); // don't forget this case!
            else {
                var nbrInserted = 0; // This will keep track of how many have been inserted
                for(var i = 0; i < results.rows.length; i++){
                    db.transaction(function (tx2) {
                        tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', [results.rows.item(i).name, new_parent_id], function() {
                            ++nbrInserted; // increment this for every insert
                            if (nbrInserted == results.rows.length) // check if complete
                                callback(); // Do your callback.
                        });
                    });
                }
            }
        });
    });
}

Что касается меня, я обнаружил, что асинхронные API WebSQL немного combersome, и поскольку базы данных WebSQL, скорее всего, исчезнут (стандарт был отброшен), я бы рекомендовал всем переключиться на SequelSphere. Это HTML5 / JavaScript реляционная база данных, которая работает во всех браузерах и на всех платформах. Он также хранит данные в localStorage, давая ему все преимущества WebSQL, без всех неприятностей.

Дайте мне знать, если описанное выше решение не работает для вас.

удачи!

Джон...