javascript 未捕获的类型错误:无法使用 indexeddb 读取 null 的属性“事务”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24256202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Uncaught TypeError: Cannot read property 'transaction' of null with an indexeddb
提问by Jerry M
I am getting an error 'Uncaught TypeError: Cannot read property 'transaction' of null ' when in this section of code
在这部分代码中,我收到错误“Uncaught TypeError: Cannot read property 'transaction' 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);
};
};
回答by Josh
remoteDB.indexedDB.db is null. This appears to be a global variable reference. In order to create a transaction, the variable must be defined, not null, and open.
remoteDB.indexedDB.db 为空。这似乎是一个全局变量引用。为了创建一个事务,变量必须被定义,不能为空,并且是打开的。
indexedDB is async. There is no guarantee that when you open a connection to indexedDB and save the handle of the connection in a global variable that the variable is still defined, not null, and open at a later point in time from within the context of another asynchronous function.
indexedDB 是异步的。无法保证当您打开到 indexedDB 的连接并将连接的句柄保存在全局变量中时,该变量仍然是定义的,而不是 null,并且在稍后的时间点从另一个异步函数的上下文中打开。
It will work sometimes, if you immediately open a transaction. Sometimes the db connection persists. But it is not guaranteed. If there are no open transactions on a database connection then the browser will close the connection at some point there after.
如果您立即打开交易,它有时会起作用。有时数据库连接仍然存在。但不能保证。如果数据库连接上没有打开的事务,那么浏览器将在之后的某个时间关闭连接。
See
看
- Why is db.transaction not working with indexeddb?
- Is it bad to open several database connections in indexedDB?
- Why is onupgradeneeded never called in this code?
- etc.
- 为什么 db.transaction 不能与 indexeddb 一起使用?
- 在 indexedDB 中打开多个数据库连接是不是很糟糕?
- 为什么在这段代码中从未调用过 onupgradeneeded?
- 等等。
This error occurs in part usually because of a programmer's lack of familiarity with asynchronous javascript. This is not a criticism, it just seems to be a common pattern. To avoid errors in the future, I suggest spending some time learning about asynchronous javascript.
发生此错误的部分原因通常是程序员不熟悉异步 javascript。这不是批评,它似乎只是一种常见的模式。为了避免将来出现错误,我建议花一些时间学习异步 javascript。
For example, understand how the following works (or rather why it does not work as expected) before trying to use indexedDB:
例如,在尝试使用 indexedDB 之前了解以下内容是如何工作的(或者更确切地说为什么它没有按预期工作):
var db;
function setDB() {
db = 123;
}
setTimeout(setDB, 10);
console.log('Got a db variable! %s', db);
To really do this justice would be redundant with the thousands of other questions on stackoverflow and insightful articles and guides on the web, but here is an extreme crash course. indexedDB.open is an asynchronous (async) function. The adjective asynchronous means alot. An async function behaves extremely differently than a synchronous function. New javascript programmers generally only learn to program synchronously. So naturally you don't get why calling an async function in your sync code does not work. Sync example:
要真正做到这一点,对于 stackoverflow 上的数千个其他问题以及网络上有见地的文章和指南来说都是多余的,但这里有一个极端的速成课程。indexedDB.open 是一个异步(async)函数。形容词异步意味着很多。异步函数的行为与同步函数截然不同。新的 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);
You know that b=2 is executed after a=1, and that sum=a+b is executed after b. The statements are executed in order, in line, in serial, one after the other, in the order you wrote them. You know that if you tried to put line 4 before line 1 above that it would not work because a and b do not yet have values. In synchronous code, you know that the function sum returns a value. It returns it immediately. So you know that abSum is immediately assigned the return value from calling sum(a,b).
你知道b=2是在a=1之后执行的,sum=a+b是在b之后执行的。这些语句按照您编写它们的顺序,按顺序、按顺序、按顺序、一个接一个地执行。您知道,如果您尝试将第 4 行放在上面的第 1 行之前,它将不起作用,因为 a 和 b 还没有值。在同步代码中,您知道函数 sum 会返回一个值。它立即返回。所以你知道 abSum 立即被分配了调用 sum(a,b) 的返回值。
Async code works extremely differently. In general, async functions do not return the value you want. Usually you pass in a function (called a callback function) to the function. An async function only sort of guarantees it will call the callback some time later. It does not return something to use.
异步代码的工作方式截然不同。通常,异步函数不会返回您想要的值。通常你将一个函数(称为回调函数)传递给函数。异步函数只能保证它会在一段时间后调用回调。它不会返回使用的东西。
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);
});
Notice that here in the working example, I don't care about what asyncSum returns. After all, it does not return the sum, it just returns a string saying it finished. Now let's do something that is more genuinely async.
请注意,在工作示例中,我不关心 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';
}
Here I really don't care about the return value of moreGenuineAsyncSum. In fact, it is worthless. It is just a string that says something. Also notice which console.log call gets executed first. The later line gets executed before the earlier line. Out of order. Out of the order in which it was written. Why is that? Because that is what async functions do, they do something at a later point in time.
这里我真的不关心 moreGenuineAsyncSum 的返回值。事实上,这是毫无价值的。它只是一个说明某些事情的字符串。还要注意哪个 console.log 调用首先被执行。较晚的行在较早的行之前执行。不正常。与它的编写顺序不符。这是为什么?因为这就是异步函数所做的,它们会在稍后的时间点做一些事情。
indexedDB.open is an async function. It returns a IDBOpenRequest object, which is a type of Request object. Most indexedDB functions are async and return Request objects. Request objects do NOT have values. They have callbacks as properties. Therefore:
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.
};
To sum this up before I write an entire book, the emphasis is on the INSIDE THE BLOCK comments above. Inside the block, the 'db' variable is guaranteed to be there, and be open, and be defined, and not null. Outside the block, the db variable does not exist.
在我写一整本书之前总结一下,重点是上面的 INSIDE THE BLOCK 评论。在块内部,'db' 变量保证在那里,并且是打开的,并且被定义,并且不为空。在块之外,db 变量不存在。
So you might be saying, that makes it pretty damn annoying to use indexedDB. You are right, it is annoying. To make it less annoying to you, you can learn about promises. Or you can write callback like functions. Or you can use one of the myriad of design patterns that deal with callback hell. There are many. One is just using a pattern like EventTarget and its relation to the DOM.
所以你可能会说,这让使用 indexedDB 变得非常烦人。你是对的,这很烦人。为了让您不那么烦人,您可以了解 Promise。或者你可以写回调函数。或者您可以使用处理回调地狱的无数设计模式之一。有许多。一种是使用像 EventTarget 这样的模式及其与 DOM 的关系。