2012-03-31 30 views
4

我正在使用PhoneGap和jQuery Mobile。我試圖從遠程位置獲取一些JSON數據,然後用它填充本地WebSQL數據庫。這裏是我的JS功能:WebSQL事務不會在JS回調函數中運行

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

} 

運行上面的功能給我一個錯誤「INVALID_STATE_ERR:DOM異常11」就行了上面提到的。當我實際嘗試使用返回的JSON數據插入數據時,它會執行相同的操作。我也嘗試了與.getJSON技術完全相同的結果。

任何意見將不勝感激!

回答

3

我會首先建議不要命名您的數據庫'tx',而是數據庫或數據庫。這可能是一個可變的命名問題,因爲函數參數和你的數據庫變量都被稱爲「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引擎。

此時,引擎注意到有一些語句已排隊並在關閉事務之前運行它們以完成操作。在你的情況下,會發生什麼事情是這樣的:

  1. 你打電話executeSql兩次排隊兩個語句。
  2. 您通過ajax請求一些東西。
  3. 將返回

發動機運行兩種說法,它已經排隊。 ajax請求也是異步運行的,但它必須訪問速度很慢的網絡,因此它可能尚未完成。此時,語句隊列爲空,並且Web SQL引擎決定是時候提交併關閉事務了!它無法知道將來會有另一個聲明!當ajax調用返回並嘗試執行INSERT INTO locations時,這太遲了,交易已經關閉。

接受的答案建議的解決方案:不要在ajax回調中使用同一個事務,而要創建一個新的。不幸的是,它有使用2個事務而不是1個事務的缺陷:操作不再是原子操作。這對您的應用程序來說可能並不重要。

如果事務的原子對你很重要,你只有2追索權是:

  • 盡一切(所有3條語句)在一個事務中的Ajax回調中。

    這是我推薦的。我認爲在創建表之前等待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 2014-11-27 10:29:38

+1

該規範的相關部分在這裏 - http://www.w3.org/TR/webdatabase/#transaction-steps – 2015-08-26 14:51:32

+0

你應該檢查下一個答案,你可能會添加第三點爲一個可能的永久解決方案:) – TechMaze 2015-09-16 19:35:14

0

當你做任何AJAX或其他異步操作時,我們確實有辦法鎖定事務。基本上在調用AJAX之前,您需要啓動一個啞元數據庫操作,並在該操作成功時檢查AJAX是否已完成,並再次調用相同的啞元操作直至完成AJAX。當AJAX完成後,您現在可以重複使用下一組executeSQL的事務對象。在article here中詳細解釋了此方法。 (我希望有人將不會刪除這個答案也一樣,有人做在前面了類似的問題)

Try this approach

+0

Won你是否會導致CPU和磁盤瘋狂地一遍又一遍地運行虛擬操作,直到AJAX完成? – Celada 2015-09-16 21:03:15

+0

我會說它不應該聽起來那麼糟糕。雖然在我的情況下,我的異步操作(而不是AJAX)耗時較少,但除此之外,反覆運行一個操作仍然會在同一個事件隊列中,因此瀏覽器不會啓動多個線程來處理CPU。我希望瀏覽器不會使文件讀取或任何昂貴的操作,如果我只是一次又一次地「選擇1」。此外,這又是一個異步操作,所以其他事件將獲得它們的時間片,下一個操作僅在第一個事件完成時排隊。 – TechMaze 2015-09-16 22:54:13