IndexedDB-初始事务未完成

时间:2019-12-29 18:21:39

标签: indexeddb

我想要一个朋友列表-页面加载时,其中三个应该出现在列表中。最初,我是使用openRequest.onsucces函数在addFriend中完成此操作的-但后来我在控制台日志中收到一条错误消息,指出该密钥已经存在。因此,我对此进行了评论,然后决定在openRequest.onupgradeneedededededededededededneedDB中添加初始值,但我无法使其工作。数据根本不会添加到有效负载上的indexedDB中。

代码如下:

(function() {
    'use strict';

    if ('indexedDB' in window) {
        let db;
        const submitButton = $('.submit');

        //indexedDB.open returns a request for a database becasue IndexedDB is asynchronous
        let openRequest = indexedDB.open('exerciseDB', 1);

        //only in 'onupgradeneeded' we can create object stores
        openRequest.onupgradeneeded = function(event) {
            //set db variable to hold the database
            db = event.target.result;
            let friendsStore = db.createObjectStore('friends');

            friendsStore.transaction.oncomplete = function(event) {
                let transaction = db.transaction(['friends'], 'readwrite'),
                    store = transaction.objectStore('friends'),
                    friends = [{ name: 'Bob', email: 'bob@bob.com'}, { name: 'Bob', email: 'bob@bob.com'},
                    { name: 'Bob', email: 'bob@bob.com'}];

                    friends.forEach(friend => store.add(friend, name));
            }
        }

        //'onsuccess' fires after 'onupgradeneeded' completes and it also fires if we refresh the page and open the database again
        openRequest.onsuccess = function(event) {
            db = event.target.result;

            // addFriend(db, 'Bob', 'bob@bob.com');
            // addFriend(db, 'Jack', 'jack@jack.com');
            // addFriend(db, 'Pete', 'pete@pete.com');

            //once the database is ready display the friends we already have
            getAndDisplayFriends(db);
        }

        openRequest.onerror = function(event) {
            console.log('error', event.target.error);
        }

        function addFriend(db, name, email) {
            //start a database transaction
            let transaction = db.transaction(['friends'], 'readwrite');
            //get the friends object store
            let store = transaction.objectStore('friends');
            let friend = {name: name, email: email};
            store.add(friend, name); //name is the key

            transaction.oncomplete = function() { 
                getAndDisplayFriends(db); 
            }

            transaction.onerror = function(event) {
                console.log('error adding friend ' + event.target.error);
            }
        }

        function getAndDisplayFriends(db) {
            let transaction = db.transaction(['friends'], 'readonly');
            let store = transaction.objectStore('friends');
            let friendsList = $('.friends');

            //create a cursor request to get all items in the store, which we collect in allFriends array
            let req = store.openCursor();
            let allFriends = [];

            req.onsuccess = function(event) {
                let cursor = event.target.result;

                if (cursor != null) {
                    allFriends.push(cursor.value);
                    cursor.continue();
                } else {
                    //if we have a null cursor, it means we've gotten all the items in the store
                    displayFriends(allFriends, friendsList);
                }
            }

            req.onerror = function(event) {
                alert('error in cursor request ' + event.target.error);
            }
        }

        function displayFriends(friendsArray = [], list) {
            //empty the list before pulling friends from database - otherwise they will be displayed multiple times
            list.empty();
            friendsArray.forEach((friend) => {
                list.append(`<li>${friend.name} - ${friend.email}`);
            });
        }

        function getFriendData() {
            const friendName = $('#friend-name').val(),
                friendEmail = $('#friend-email').val();

            addFriend(db, friendName, friendEmail);
        }

        function bindUiEvents() {
            submitButton.on('click', (event) => {
                event.preventDefault();
                getFriendData();
            });
        }

        bindUiEvents();
    }
}())

1 个答案:

答案 0 :(得分:1)

您不必等待添加好友操作将数据存储在数据库中并在尝试查询数据库之前完成操作。在我看来,您需要花一些时间来学习异步javascript。

但是,学习异步代码的工作方式可能需要一段时间,并且充满挑战。因此,为了尽快为您解决问题,尽管它不够优雅,并且没有真正解释其工作原理,我建议您重写代码,如下所示:

function dothings() {
  var openRequest = indexedDB.open(...);
  openRequest.onsuccess = function(event) {
    var db = event.target.result;
    var tx = db.transaction(...);
    var store = tx.objectStore(...);
    for (var friend of friends) {
      store.add(friend);
    }

    // and here is the solution to your problem, the trick is that we only start 
    // another transaction once the first one completes
    tx.oncomplete = function(event) {
      var tx2 = db.transaction(...);
      var store2 = tx2.objectStore(...);
      var request = store2.getAll();
      request.onsuccess = function(event) {
        var friends = event.target.result;
        for (var friend of friends) {
          addFriendToHTML(friend);
        }
      };
    };
  };
}

编辑:我只是再次阅读我的答案,不确定我是否提供了足够的帮助。问题出在您原始的注释代码中。以下是一些可能有助于澄清的事情:

  1. 您可以为每个addFriend进行一次事务,而您只能对所有这些事务使用一个事务。
  2. 您正在呼叫getAndDisplayFriends,然后等待所有addFriend呼叫完成。
  3. 在新代码中,看起来您只是在onupgradeneeded处理程序中插入数据库升级,但是您并不想每次都想增加好友来增加版本,因此您永远不会触发任何插入。

您有几种选择:

  • 回头看看我给出的示例代码,如果您确实遇到困难,它会起作用,或者
  • 更改代码,编写添加所有朋友的函数addFriends,然后在交易完成时调用回调函数,然后仅在该回调函数中进行调用getAndDisplayFriends
  • 如果您愿意使用诺言,我们可以真正清理代码,逻辑将变得更加清晰,如果您愿意,我可以为您提供帮助