使用indexedDB返回'undefined'

时间:2018-02-19 11:17:05

标签: javascript indexeddb

我正在尝试使用indexedDB。

我的代码的某些部分有效。

在以下示例中,第一个函数在我的数据库中添加服务器,但是在Chrome调试控制台中,有一条undefined消息与任何行无关。已经添加了服务器。

第二个函数将记录放入数组中,还有一条undefined消息与任何行无关。

如果我在console.log(servers);之前做return servers;我可以看到数组内容,但是如果我在我的代码中的其他地方调用该函数,则返回的对象为undefined

var dbName = 'myDBname',
dbServersStoreName = 'servers',
dbVersion = 1,
openDBforCreation = indexedDB.open(dbName, dbVersion);

openDBforCreation.onupgradeneeded = function(e) {
 var db = e.target.result;
 var objStore = db.createObjectStore(dbServersStoreName, { keyPath: "alias" 
});
var index = objStore.createIndex("serversAlias", ["alias"]);
};

function addServerInDB(serverAlias,serverAddress,user,pwd){
 var myDB = indexedDB.open(dbName, dbVersion);

 myDB.onerror = function() {
  var notification = document.querySelector('.mdl-js-snackbar');
   notification.MaterialSnackbar.showSnackbar(
    {message: 'Error while trying to access internal database'});
}
myDB.onsuccess = function(e) {
 var db = e.target.result,
     request = db.transaction([dbServersStoreName], 
               "readwrite").objectStore("servers")
                .put({alias:''+serverAlias+'', 
                address:''+serverAddress+'', login:''+user+'', 
                passwd:''+pwd+''});

     request.onsuccess = function(){
      var notification = document.querySelector('.mdl-js-snackbar');
       notification.MaterialSnackbar.showSnackbar(
        {message: 'Server added'});
     }
 }
};

function listServersInDB(){
 var myDB= indexedDB.open(dbName, dbVersion);

myDB.onerror = function() {
    var notification = document.querySelector('.mdl-js-snackbar');
    notification.MaterialSnackbar.showSnackbar(
        {message: 'Error while trying to access internal database'});

}
myDB.onsuccess = function(e) {
    var servers = new Array(),
        db = e.target.result,
        request = db.transaction(["servers"], "readwrite")
                    .objectStore("servers")
                    .openCursor();

    request.onsuccess = function(e){
        var cursor = e.target.result;
        if(cursor){
            servers.push(cursor.value);
            cursor.continue();
        }
        return servers;
    }
}
};

我不明白这个undefined来自哪里,如果这就是listServersInDB()函数不起作用的原因。

2 个答案:

答案 0 :(得分:3)

您需要了解有关如何编写异步Javascript的更多信息。您的代码中有太多错误甚至无法开始推理问题。

简而言之,不要这样做:

function open() {
  var openDatabaseRequest = ...;
}

openDatabaseRequest.foo = ...;

相反,这样做:

function open() {
  var openDatabaseRequest = ...;
  openDatabaseRequest.foo = ...;
}

接下来,您不需要多次尝试打开同一个数据库。你为什么两次调用indexedDB.open?您可以打开数据库以安装它并立即开始使用它。全部使用相同的连接。

接下来,我建议您不要将数据库打开请求命名为“myDB”。这是误导。这是一个IDBRequest对象,更具体地说,是一个IDBOpenRequest对象。请求不是数据库。

接下来,您无法从最终的request.onsuccess返回servers数组。对于一个这回到无处可能是未定义的来源。每次光标前进时都返回两次,因此多次返回返回服务器完全没有意义。三是这太早返回,因为它在枚举所有服务器之前无法返回。要正确返回,您需要等到列出所有服务器。这意味着使用异步代码模式。例如,以下是使用回调的方法:

function listServers(db, callbackFunction) {
  var servers = [];
  var tx = db.transaction(...);
  var store = tx.objectStore(...);
  var request = store.openCursor();

  request.onsuccess = function() {
    var cursor = request.result;
    if(cursor) {
      servers.push(cursor.value);
      cursor.continue();
    }
  };

  tx.oncomplete = function() {
    callbackFunction(servers);
  };

  return 'Requested servers to be loaded ... eventually callback will happen';
}


function connectAndList() {
  var request = indexedDB.open(...);
  request.onsuccess = function() {
    var db = request.result;
    listServers(db, onServersListed);
  };
}

function onServersListed(servers) {
  console.log('Loaded servers array from db:', servers);
}

当您调用不返回值的函数时,它将返回undefined。除非您明确返回其他内容,否则JavaScript中的所有函数都将返回undefined。

当你从devtools控制台调用一个函数,并且该函数返回undefined时,控制台会输出' - >未定义”。这是使用控制台的一个普通方面。

如果你想获得一个将服务器列表作为数组返回的函数,那么你不能。以假装的方式做到这一点的唯一方法是使用“异步”功能和承诺。

async function getServers() {
  var db = await new Promise(resolve => {
    var request = indexedDB.open(...);
    request.onsuccess = () => resolve(request.result);
  });

  var servers = await new Promise(resolve => {
    var tx = db.transaction(...);
    var request = tx.objectStore(...).getAll();
    request.onsuccess = () => resolve(request.result);
  });
  return servers;
}

再一次编辑,如果要从控制台调用此功能,请使用await getServers();。如果您不在控制台中使用顶级await,那么您将获得async函数的典型返回值,该函数是Promise对象。要将承诺变为其返回值,您必须等待它。

答案 1 :(得分:0)

明确且有帮助的解释,谢谢。

我多次打开数据库,因为第一次检查数据库是否需要升级并在需要时执行某些操作。我将在每个函数中添加'db.close()'。

然后,我尝试了你的例子,结果是一样的: console.log('Loaded servers array from db:', servers);有效 但是return servers;不行。

在控制台中已经有一个没有相关行的undefined

Screenshot