3

我觉得这是一件很平凡的事情。我想更新 IndexedDB 数据库中的对象,然后运行一些代码,然后使用更新的值。

我最初所做的只是在调用 之后运行我的回调函数cursor.update,这在 Firefox 中有效。但它在 Chrome 中失败,在运行以下代码之前不会发生更新。这可能是一种竞争条件,因为(据我所知)更新是异步的。

所以我想我应该使用onsuccess信号cursor.update来调用我的回调函数。但令我惊讶的是,这似乎在 Chrome 中也不起作用!

您可以在 jsFiddle 上运行的一些示例代码......虽然有趣的是,由于某种原因,这似乎在 jsFiddle 中的 Firefox 中崩溃了,但 Chrome 工作正常;对于 Firefox,您可以在本地运行它并且它可以工作(这会在浏览器的 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}

在 Chrome 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,我想知道它在这种情况下的表现如何..

4

2 回答 2

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 令人困惑的方面之一。请求 onsuccess 并不意味着您的成功已写入数据库。只有交易完成确认。原因是,您仍然可以tx.abort()在写入请求后中止事务。

于 2013-03-01T10:40:12.563 回答
0

我使用 promise 模式来避免 settimeout 和JayData 库来统一数据访问和隐藏光标 API。包含库(include.jaydata.org/jaydata.min.js)后,代码片段如下所示(在线 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 :)

于 2013-03-01T09:19:24.933 回答