使用 indexedDB returns 'undefined'

Use of indexedDB returns 'undefined'

我正在尝试使用 indexedDB。

我的部分代码有效。

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

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

如果我在 return servers; 之前执行 console.log(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() 功能不起作用的原因。

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

简单地说,不要这样做:

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

openDatabaseRequest.foo = ...;

相反,这样做:

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

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

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

接下来,您不能 return 来自最后 request.onsuccess 的服务器数组。其中一个 returns 无处可去,可能是未定义的来源。每次游标前进时都会有两个 returns,因此多次 return return 服务器毫无意义。三是这个 return 太早了,因为它不能 return 直到所有服务器都被枚举。要正确 return 你需要等到所有服务器都列出来。这意味着使用异步代码模式。例如,这里是你如何使用回调来完成它:

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);
}

当您调用一个没有 return 值的函数时,它 return 是未定义的。 JavaScript return 中的所有函数均未定义,除非您明确 return 其他内容。

当您从 devtools 控制台调用一个函数,并且该函数 return 未定义时,控制台会打印出“-> undefined”。这是使用控制台的一个普通方面。

如果您想获得一个函数,return将服务器列表作为一个数组,那么,您不能。以假装的方式做到这一点的唯一方法是使用 'async' 函数和承诺。

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();。如果您不在控制台中使用 top-level await,那么您将获得异步函数的典型 return 值,它是一个 Promise 对象。要将承诺转化为它的 return 值,您必须等待它。

清晰有用的解释,谢谢。

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

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

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

Screenshot