2012-03-31 20 views
4

私はPhoneGapとjQuery Mobileを使用しています。リモートの場所からいくつかのJSONデータを取得し、ローカルのWebSQLデータベースにそのデータを設定しようとしています。ラインは、上記に:JSコールバック関数でWebSQLトランザクションが実行されない

function getLocations() { 

    var tx = window.openDatabase('csdistroloc', '1.0', 'Distro DB', 1000000); 
    tx.transaction(function(tx) { 
     tx.executeSql('DROP TABLE IF EXISTS locations'); //this line works! 
     tx.executeSql('CREATE TABLE IF NOT EXISTS locations (id, name, address, postalcode, phone, category)'); //this line works! 

     $.ajax({ 
      url: "http://mydomain.com/api.php", 
      dataType: 'json', 
      data: { action: "getlocations" }, 
      success: function(data) { 
      tx.executeSql("INSERT INTO locations (id, name, address, postalcode, phone, category) VALUES (2,'cheese','232','seven',5,6)"); //this line produces an error 
     }}); 

    }, dberror, dbsuccess); 

} 

上記の関数を実行している私にエラー「DOM例外11 INVALID_STATE_ERR」を与える:ここに私のJS関数です。実際に返されたJSONデータを使用してデータを挿入しようとしているときも同じことが行われます。私も$ .getJSONテクニックと全く同じ結果を試しました。

アドバイスをいただければ幸いです!

答えて

3

まず、データベースに「tx」という名前ではなく、dbまたはデータベースという名前を付けることをお勧めします。関数のパラメータとデータベースの変数の両方が

EDIT「TX」と呼ばれているので、これは変数の命名問題である可能性があります:私はこの同じ問題を抱えていたし、それが自分のトランザクションのコールバック内のクエリを作ることによってそれを解決しました。これと同じように:

success: function(data) { 
tx.transaction(function(transaction){ 
    transaction.executeSql("INSERT INTO locations (id, name, address, postalcode, phone, category) 
VALUES (2,'cheese','232','seven',5,6)"); //now more DOM exception! 
    } 
}} 

私はこの問題は、コールバックがwebSQLのトランザクションが同期していないので、外側のトランザクションが完了した発射される時間であると思います。

6

accepted answerが正しいですが、私は同じ問題に遭遇し、OPはそれを持っていたとして、それが動作しない理由をその答えはを言っていないので、私はそれに拡大したいと思います。

Web SQLでトランザクションを作成すると、トランザクション処理は、there are any statements queued up in the transactionの間だけ有効です。トランザクション内の文のパイプラインが枯渇するとすぐに、エンジンはトランザクションをクローズ(コミット)します。考えられるのは、function(tx) { ... }コールバックが実行されるとき、

  1. これは、必要なすべてのステートメントを実行するということです。 executeSqlは非同期なので、文がまだ実行されていなくてもすぐに戻ります。
  2. Web SQLエンジンに制御を戻します。

この時点で、エンジンは、トランザクションをクローズする前に、キューに入れられたステートメントが完了していることを認識し、完了まで実行します。あなたは二つの文をキューするために二回executeSqlを呼び出す

  1. :あなたのケースでは、何が起こるかは、このです。
  2. あなたはajaxで何かをリクエストします。
  3. あなたは

を返すエンジンは、それがキューに入れられたことを二つの文を実行します。 ajaxリクエストも非同期的に実行されていますが、遅いネットワークにアクセスする必要があるため、まだ完了していない可能性があります。この時点では、文のキューは空であり、Web SQLエンジンはトランザクションをコミットして終了する時点であると判断します。それは後で来る別の声明があることを知る方法がありません! ajax呼び出しが戻り、INSERT INTO locationsを実行しようとするまでには、遅すぎます。トランザクションはすでに閉じられています。

受諾された回答によって提案された解決策が機能します:ajaxコールバック内で同じトランザクションを使用せずに新しいトランザクションを作成します。残念ながら、1の代わりに2つのトランザクションを使用すると予想される落とし穴があります。操作はもはや原子的ではありません。それはあなたのアプリケーションにとって重要かもしれませんし、重要ではないかもしれません。

トランザクションの原子があなたのために重要である場合は、あなたの唯一の2 recoursesは以下のとおりです。

  • は、Ajaxコールバック内の1つのトランザクションでのすべて(すべての3文)を行います。

    これは私が推奨するものです。私は、テーブルを作成する前にajaxリクエストが完了してからアプリケーションの要件に適合するまで待機する可能性が非常に高いと思います。

  • 同期的にajaxリクエストを実行しますas explained here

    私はそれをお勧めしません。 JavaScriptでの非同期プログラミングは、良いものです。ところで

、私はこのような何かを見て、コードで、約束の文脈で問題が発生しました:

// XXX don't do this, it doesn't work! 
db.transaction(function(tx) { 
    new Promise(function(resolve, reject) { 
     tx.executeSql(
      "SELECT some stuff FROM table ....", [], 
      function(tx, result) { 
       // extract the data that are needed for 
       // the next step 
       var answer = result.rows.item(....).some_column; 
       resolve(answer); 
      } 
     ) 
    }).then(function(answer) { 
     tx.executeSql(
      "UPDATE something else", 
      // The answer from the previous query is a parameter to this one 
      [ ... , answer, .... ] 
     ) 
    }); 
}); 

を問題は約束して、チェーン.then()句ではない、ということです当初の約束を直ちに実行する。これは、ajaxリクエストと同様に、後で実行するためだけにキューに入れられます。唯一の違いは、遅いajaxリクエストとは異なり、.then()句がほぼ即座に実行されることです。しかし、「ほとんど」は十分ではありません。トランザクションが閉じられる前に、すぐに次のSQL文をキューに入れることができるかもしれません。したがって、コードは、タイミングおよび/またはブラウザの実装に応じて無効状態エラーを生成してもしなくてもよい。

あまりにも悪い:Promiseは、SQLトランザクション内で使用すると便利でした。上記の擬似例は、約束なしに簡単に書き直すことができますが、多くの.then()のチェーンやPromise.allなどのチェーンを利用するケースもあります。これは、SQL文のコレクション全体がどの順序で実行されているかを完全に確認できますその他の声明の前に

+0

(誰かが同様の問題に以前行ったように、私は、誰かがあまりにもこの回答を削除しないことを願っています)、私は基本的に[同じ答え]を書いた(http://stackoverflow.com/questions/12265003/phonegap-invalid-state-err-dom-exception-11/27168338#27168338)を別の質問に追加します。 – Celada

+1

仕様の関連部分はここにあります - http://www.w3.org/TR/webdatabase/#transaction-steps –

+0

次の答えを確認してください。可能な永久的な解決策のために3点目を追加してください:) – TechMaze

0

AJAXやその他の非同期操作を実行している間は、トランザクションをロックする方法があります。基本的にAJAXを呼び出す前に、ダミーのDB操作を開始し、AJAXが完了したかどうかをその操作チェックで成功させ、再度AJAXが完了するまで同じダミー操作を呼び出す必要があります。 AJAXが完了すると、次のexecuteSQLのセットをトランザクションオブジェクトから再利用できるようになりました。このアプローチは、article hereで完全に説明されています。 FYI

Try this approach

+0

AJAXが完了するまで、CPUとディスクが狂ってダミー操作を何度も繰り返し実行させてしまうのですか? – Celada

+0

私はそれが聞こえるほど悪くあってはならないと言います。私の場合、私は時間のかかる非同期操作(AJAXではなく)が少ないですが、何度も何度も何度も操作を実行すると同じイベントキューに置かれるため、ブラウザはCPUを浪費するために複数のスレッドを開始しません。私はちょうど "select 1"を何度も何度もやると、ブラウザはファイルの読み込みや高価な操作をしないことを望んでいます。さらに、これは非同期操作であるため、他のイベントはタイムスライスを取得し、次の操作は最初の操作が完了したときにのみキューに入れられます。 – TechMaze

関連する問題