8

比較的簡単な質問があると思いますが、私は輪になって考え続けており、Googleでさえ私が取り組むことができる答えを私に与えていません。

基本的に、WebSQLを使用してローカルに保存されているいくつかのレコードをコピーしようとしています。コピーは問題ではありませんが、プログラムを続行する前に、すべてのコピーアクションがいつ終了するかを知る必要があります。

WebSQL呼び出しは非同期で行われるため、通常これらのことを行う唯一の方法は、コールバック関数を使用することです。ただし、クエリは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ループが完了したときにのみコールバック関数が呼び出されるようにする方法についてのヘルプをいただければ幸いです。

前もって感謝します。

4

2 に答える 2

8

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();
    }
})();
于 2012-10-17T15:38:17.653 に答える
2

これは、「コールバック」関数の実行回数をカウントし、結果セットの全量に達した場合にのみ続行することによって行うのが最適です。

変更を加えたコードは次のとおりです。

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.
                        });
                    });
                }
            }
        });
    });
}

私としては、WebSQL の非同期 API は少し扱いに​​くいと感じました。WebSQL データベースはなくなる可能性が高いため (標準は廃止されました)、すべての人にSequelSphereに切り替えることをお勧めします。これは、すべてのブラウザーとすべてのプラットフォームで動作する HTML5 / JavaScript リレーショナル データベースです。また、データを localStorage に格納することで、手間をかけずに WebSQL のすべての利点を得ることができます。

上記の解決策がうまくいかない場合はお知らせください。

幸運を!

ジョン...

于 2012-10-17T15:27:48.487 に答える