运行代码的对象在索引资料(特别是在铬)仅更新后(Running code only after an

2019-07-20 18:37发布

我觉得这是做一个非常平凡的事。 我想在IndexedDB的数据库更新一个对象,然后运行一些代码之后,使用更新后的值。

我本来打完电话后只是运行我的回调函数cursor.update ,这在Firefox的作品。 但它无法在Chrome中,运行下面的代码之前的更新不会发生。 这可能是一个竞争条件,因为(据我所知)更新是异步的。

于是我想我应该使用onsuccess的信号cursor.update打电话给我的回调函数。 但令我惊讶的是,这也似乎没有在Chrome工作!

一些示例代码, 你可以在运行的jsfiddle ...虽然可笑,这似乎在Firefox崩溃中的jsfiddle出于某种原因,但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 )。

替代的问题:我是不是做错了什么,或者这是浏览器的错误?

侧问题:如果任何人有IE 10,我不知道它的行为在这种情况下..

Answer 1:

你不需要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);
   };
 }

这是索引资料API的混乱方面之一。 请求的onSuccess不要吝啬你的成功是写入到数据库中。 只有交易的onComplete确认。 原因是,你仍然可以中止交易tx.abort()写入请求后。



Answer 2:

我用的承诺模式,以避免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 :)



文章来源: Running code only after an object is updated in IndexedDB (particularly in Chrome)