3

我覺得這是一件非常平凡的事情。我想更新IndexedDB數據庫中的對象,然後運行一些代碼,然後使用更新後的值。僅在IndexedDB中更新對象後才運行代碼(特別是在Chrome中)

我最初做的是在調用cursor.update之後運行我的回調函數,這個工作在Firefox中。但在Chrome中失敗,在下面的代碼運行之前更新不會發生。這可能是一種競爭條件,因爲(據我所知)更新是異步的。

因此,我認爲我應該使用的onsuccess信號來調用我的回調函數。但令我驚訝的是,這似乎也不適用於Chrome!

一些示例代碼you can run on jsFiddle... although amusingly this seems to crash in Firefox in jsFiddle for some reason, but Chrome works fine; for Firefox you can run it locally and it works(這將產生JavaScript控制檯在您的瀏覽器輸出):

<html> 
<head> 
<script> 
var db, request; 

request = indexedDB.open("test", 1); 
request.onupgradeneeded = function (event) { 
    var i, leagueStore, teams, teamStore; 

    db = event.target.result; 

    objectStore = db.createObjectStore("objects", {keyPath: "id"}); 
}; 
request.onsuccess = function (event) { 
    db = request.result; 

    // Add some dummy data 
    db.transaction("objects", "readwrite").objectStore("objects").put({ 
     id: 0, 
     value: 42 
    }); 

    // Update data 
    db.transaction("objects", "readwrite").objectStore("objects").openCursor(0).onsuccess = function (event) { 
     var cursor, object; 

     cursor = event.target.result; 
     object = cursor.value; 
     object.value = 43; 
     cursor.update(object).onsuccess = function (event) { 
      db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) { 
       console.log("Cursor update onsuccess event:"); 
       console.log(event.target.result); 
      }; 
     }; 

     // Read back updated data 
     db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) { 
      console.log("The line after the cursor update:"); 
      console.log(event.target.result); 
     }; 

     // Wait a little bit, then read it back 
     setTimeout(function() { 
      db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) { 
       console.log("After an additional delay via setTimeout:"); 
       console.log(event.target.result); 
      }; 
     }, 100); 
    }; 
}; 
</script> 
</head> 
</html> 

觀察到的行爲(所有在Ubuntu 12.10,FWIW):

在Firefox 19(當前穩定版),所有三個記錄的對象是相同的,value設定爲43:

The line after the cursor update: 
Object {id: 0, value: 43} 
Cursor update onsuccess event: 
Object {id: 0, value: 43} 
After an additional delay via setTimeout: 
Object {id: 0, value: 43} 

在鉻25(電流穩定版本)和27(當前不穩定的版本),我通常會得到這樣的輸出:

The line after the cursor update: 
Object {id: 0, value: 42} 
Cursor update onsuccess event: 
Object {id: 0, value: 42} 
After an additional delay via setTimeout: 
Object {id: 0, value: 43} 

有時前兩個輸出中的一個被更新爲43,但它通常是一個42

如此反覆,我的問題是...更新完成後我怎麼能運行一些東西? (也就是說,不依靠setTimeout誘發的一些荒謬的任意延遲。)

替代問題:我做錯了什麼,或者這是Chrome中的錯誤?

方的問題:如果任何人有IE 10,我不知道它的行爲在這種情況下..

回答

8

你不需要setTimeout的,只是等待交易完成如下:

// Update data 
var tx = db.transaction("objects", "readwrite"); 

tx.objectStore("objects").openCursor(0).onsuccess = function (event) { 
    var cursor, object; 

    cursor = event.target.result; 
    object = cursor.value; 
    object.value = 43; 
    cursor.update(object).onsuccess = function (event) { 
     db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) { 
      console.log("Cursor update onsuccess event:"); 
      console.log(event.target.result); 
     }; 
    }; 

}; 

tx.oncomplete = function() {  
    // Read back updated data 
    db.transaction("objects").objectStore("objects").get(0).onsuccess = function (event) { 
     console.log("The line after the cursor update:"); 
     console.log(event.target.result); 
    }; 
} 

這是IndexedDB API的混亂方面之一。申請成功並不意味着您的成功寫入數據庫。只有交易完成確認。原因是,在寫入請求後,您仍然可以放棄交易tx.abort()

+0

謝謝。一個輔助問題然後..是否有任何用於更新的獲取信號的用途?還是隻是在那裏混淆了我? – dumbmatter 2013-03-01 14:42:26

0

我使用的承諾模式,以避免setTimeout和JayData library統一的數據訪問和隱藏光標API。 包括圖書館(include.jaydata.org/jaydata.min.js)的片段看起來像這樣(online jsfiddle)後:

$data.Entity.extend("Todo", { 
    Id: { type: "int", key: true, computed: true }, 
    Task: { type: String, required: true, maxLength: 200 } 
}); 

$data.EntityContext.extend("TodoDatabase", { 
    Todos: { type: $data.EntitySet, elementType: Todo } 
}); 

var todoDB = new TodoDatabase({ 
    provider: 'indexedDb', databaseName: 'MyTodoDatabase' 
}); 

todoDB.onReady(function() { 
    var newTodo = new Todo({Task: "alma"}); 
    todoDB.Todos.add(newTodo); 
    todoDB.saveChanges() 
    .then(function() { 
     console.log("Initial value: ", newTodo.Task); 
     todoDB.Todos.attach(newTodo); 
     newTodo.Task = "korte"; 
     return todoDB.Todos.saveChanges(); 
    }) 
    .then(function(){ 
     console.log("Updated value: ", newTodo.Task); 
     return todoDB.Todos 
     .filter(function(t) {return t.Id == item.Id;}, {item: newTodo}) 
     .toArray(function(dbResult){ 
      var todoFromDb = dbResult[0]; 
      console.log("Value from DB: ", todoFromDb.Task); 
     }); 
    }) 


}); 

這少得多的代碼,你只需要改變供應商的類型改變的WebSQL :)

相關問題