我收到错误'未捕获的类型错误:无法读取属性'事务' of null' 在这部分代码中
remoteDB.indexedDB.addAdmins = function() {
var db = remoteDB.indexedDB.db;
var trans = db.transaction("students", "readwrite");
var request = trans.objectStore("administrators");
/*
this section edited out since the failure is on line 3
*/
request.onsuccess = function(e) {
console.log("success Adding: ", e);
};
request.onerror = function(e) {
console.log(e.value);
};
};
答案 0 :(得分:11)
remoteDB.indexedDB.db为null。这似乎是一个全局变量引用。为了创建事务,必须定义变量,而不是null,并且打开。
indexedDB是异步的。无法保证当您打开与indexedDB的连接并在全局变量中保存连接句柄时,该变量仍然定义,而不是null,并在稍后的时间点从另一个异步函数的上下文中打开。
如果您立即开启交易,它有时会起作用。有时数据库连接仍然存在。但它不能保证。如果数据库连接上没有打开的事务,那么浏览器将在之后的某个时刻关闭连接。
见
这个错误部分通常是因为程序员对异步javascript缺乏熟悉。这不是批评,它似乎只是一种常见的模式。为避免将来出现错误,我建议花一些时间学习异步javascript。
例如,在尝试使用indexedDB之前,请了解以下内容如何工作(或者更确切地说,为什么它不能按预期工作):
var db;
function setDB() {
db = 123;
}
setTimeout(setDB, 10);
console.log('Got a db variable! %s', db);
要真正做到这一点,在网络上有关于stackoverflow和富有洞察力的文章和指南的成千上万的其他问题,正义将是多余的,但这是一个极端的速成课程。 indexedDB.open是一个异步(异步)函数。形容词异步意味着很多。异步函数的行为与同步函数的行为完全不同。新的javascript程序员通常只学习同步编程。很自然地,你不知道为什么在同步代码中调用异步函数不起作用。同步示例:
var a = 1;
var b = 2;
function sum(arg1, arg2) { return arg1 + arg2 }
var abSum = sum(a,b);
console.log('The sum of a + b is %s', abSum);
你知道在a = 1之后执行b = 2,并且在b之后执行sum = a + b。这些语句按顺序,按行,按顺序依次执行,按照您编写的顺序执行。你知道,如果你试图将第4行放在第1行之前,它将无法工作,因为a和b还没有值。在同步代码中,您知道函数sum返回一个值。它会立即返回。所以你知道abSum会立即从调用sum(a,b)中分配返回值。
异步代码的工作方式截然不同。通常,异步函数不会返回所需的值。通常将函数(称为回调函数)传递给函数。异步函数只保证它会在稍后调用回调。它不会返回一些东西。
var a = 1;
var b = 2;
function asyncSum(arg1,arg2,calledWhenFinished) {
var sum = arg1+arg2;
calledWhenFinished(sum);
return 'asyncSumFinished and called the callback';
}
// The following DOES NOT work as expected
var theResultOfSum = asyncSum(a,b, function(sum) {
console.log('finished. The um is %s', theResultOfSum);
});
// The following DOES work as expected
asyncSum(a,b, function(sum) {
console.log('The sum is %s', sum);
});
请注意,在工作示例中,我并不关心asyncSum返回的内容。毕竟,它不会返回总和,它只返回一个字符串,表示它已完成。现在让我们做一些更真实的异步。
function moreGenuineAsyncSum(a,b, callback) {
setTimeout(function() {
var sum = a + b;
console.log('The sum is %s', sum);
callback(sum);
}, 100);
console.log('Requested the sum to be calculated');
return 'Hey, I scheduled the callback function to execute in 100ms';
}
在这里,我真的不关心moreGenuineAsyncSum的返回值。事实上,它毫无价值。这只是一个字符串。还要注意首先执行哪个console.log调用。后一行在前一行之前执行。故障。不按照它的编写顺序。这是为什么?因为这是异步函数所做的事情,所以它们会在以后的某个时间点执行某些操作。
indexedDB.open是一个异步函数。它返回一个IDBOpenRequest对象,它是一种Request对象。大多数indexedDB函数都是异步并返回Request对象。请求对象没有值。他们将回调作为属性。因此:
var dbRequest = indexedDB.open('mydb',1);
dbRequest.onsuccess = function(event) {
// This gets called later. The following are all viable ways to get the IDBDatabase
// object INSIDE THE BLOCK OF THIS FUNCTION ONLY. Any one of the following 3 lines
// works exactly the same way.
var db = this.result;
var db = dbRequest.result;
var db = event.target.result;
console.log('Got a db connection! It is %s', db);
// Now, INSIDE THE BLOCK OF THIS FUNCTION ONLY, do something:
var myTransaction = db.transaction('myObjectStore','readwrite');
var myObjectStore = myTransaction.objectStore('myObjectStore');
// etc.
};
在我写完整本书之前总结一下,重点是上面的INSIDE THE BLOCK评论。在街区内,' db'变量保证在那里,并且是开放的,并且被定义,而不是null。在块之外,db变量不存在。
所以你可能会说,这使得使用indexedDB非常烦人。你是对的,这很烦人。为了减少对你的烦恼,你可以了解承诺。或者你可以像函数一样编写回调函数。或者你可以使用处理回调地狱的无数设计模式之一。有许多。一种是使用像EventTarget这样的模式及其与DOM的关系。