Javascript IndexedDB包含两个事务:1个读取,1个更新
使用IndexedDB,我似乎无法在已经创建了用于读取和显示数据的事务之后,为objectstore创建第二个事务(只是ToDo的列表)。我没有在尝试创建第二个事务的行中得到错误,但是什么都没有发生,代码停止执行 检索和显示我的数据的此部分运行良好:Javascript IndexedDB包含两个事务:1个读取,1个更新,javascript,indexeddb,Javascript,Indexeddb,使用IndexedDB,我似乎无法在已经创建了用于读取和显示数据的事务之后,为objectstore创建第二个事务(只是ToDo的列表)。我没有在尝试创建第二个事务的行中得到错误,但是什么都没有发生,代码停止执行 检索和显示我的数据的此部分运行良好: var trans; var ostore; var db; var reqdb = window.indexedDB.open("ToDoApp", 2); reqdb.onupgradeneeded = function (event) {
var trans;
var ostore;
var db;
var reqdb = window.indexedDB.open("ToDoApp", 2);
reqdb.onupgradeneeded = function (event) {
console.log("running onupgradeneeded");
var myDB = event.target.result;
if (!myDB.objectStoreNames.contains("todos")) {
myDB.createObjectStore("todos", { keyPath: "ToDoTitle" });
}
};
reqdb.onsuccess = function (event) {
db = event.target.result;
trans = db.transaction(["todos"], "readonly");
ostore = trans.objectStore("todos");
var req = ostore.get("TEST IDB 2");
$("#btnSave").click(function () {
UpdateToDo();
});
req.onerror = function (event) {
alert("error");
};
req.onsuccess = function (event) {
$("#ToDoTitle").val(req.result.ToDoTitle);
};
};
这可以很好地获取和显示内容。但是请注意UpdateToDo()函数,它通过onclick事件进行设置,因此我可以实际更新数据
function UpdateToDo(event) {
alert("1");
var newtransaction = db.transaction(["todos"], "readwrite");
alert("2");
var newstore = newtransaction.objectStore("todos");
newstore.openCursor().onsuccess = function (event) {
const cursor = event.target.result;
if (cursor) {
if (cursor.value.ToDoTitle == 'TEST IDB 2') {
const updateData = cursor.value;
updateData.ToDoCategory = 1; // hard coding for now
var requpdate = cursor.update(updateData);
requpdate.onsuccess = function () {
console.log('Updated');
};
requpdate.onerror = function () {
console.log('Error');
}
};
cursor.continue();
} else {
console.log('Cursor error.');
}
};
}
第一个警报触发,但第二个警报没有。我假设,因为创建第一个事务的第一个回调被返回,所以该事务被关闭,但它似乎仍然阻止我创建该事务。如果我完全取出第一个事务,将创建第二个事务并运行第二个警报。。。然后我可以从那里创建一个游标并更新数据
我尝试将第一个事务和对象存储作为全局变量,但这也不起作用
每页只允许您执行一个事务似乎有点可笑。否则,我将如何开始加载数据,然后允许用户更新数据?我错过了什么吗?伊斯干达和我在同一时间有着相同的想法。在UpdateToDo函数中,我打开了一个与IndexedDB实例完全分离的连接,并使我的新事务/存储连接到该实例。。处理这一请求成功了
function UpdateToDo() {
var udb = window.indexedDB.open("ToDoApp", 2);
alert("1");
udb.onsuccess = function (event) {
alert("2");
db2 = event.target.result;
var trans2 = db2.transaction(["todos"], "readwrite");
var ostore2 = trans2.objectStore("todos");
alert("3");
var blabla = ostore2.openCursor();
blabla.onsuccess = function (event2) {
在MS Sql Server/ASP.NET背景下,打开到同一数据库的多个连接感觉很不直观 似乎IndexedDB和Cache API在Safari上直到去年才真正稳定,而服务人员直到去年(2018年)才被纳入Safari。虽然Android在全球市场占有一席之地,但在北美,如果苹果不支持它,就不会有太多的发展。。。它在某种程度上解释了这些新功能的最后一个文档和教程。祝大家好运只要几点:
- 不将
与indexedDb调用一起使用。indexedDB是异步的<代码>警报不是异步的,它会在显示时停止执行,这可能会导致一些奇怪的行为。最好使用console.log,因为这不会停止执行警报
- 不要在同一个函数(或嵌套函数)中混合执行DOM修改的代码和执行数据库查询的代码。我会把你的项目代码组织成更小的函数,只做一件事
- 不使用全局数据库变量。而是每次打开数据库。打开数据库一次,然后单击创建一个或多个事务可以工作,但我建议您根据需要每次创建数据库连接
- 考虑使用一个事务。您可以在同一事务上发出读取和写入请求
- 如果您的部署环境支持异步/等待,请考虑将其与承诺一起使用。如果操作正确,您的代码将变得非常可读
- 如果您只是更新一个值,请使用
而不是IDBObjectStore.prototype.get
openCursor
- 在readwrite txn中执行写入请求时,大部分时间监听请求成功表示成功,但并不总是如此,因此最好监听txn complete事件
function connect(name, version, upgrade) {
return new Promise((resolve, reject) => {
var req = indexedDB.open(name, version);
req.onupgradeneeded = upgrade;
req.onsuccess = event => resolve(req.result);
req.onerror = event => reject(req.error);
});
}
function onupgradeneeded(event) {
var db = event.target.result;
db.createObjectStore(...);
}
function updateTodo(db, todo) {
return new Promise((resolve, reject) => {
var tx = db.transaction('todos', 'readwrite');
tx.onerror = event => reject(event.target.error);
tx.oncomplete = resolve;
var store = tx.objectStore('todos');
var req = store.get(todo.title);
req.onsuccess = event => {
// When using get instead of openCursor, we just grab the result
var old = event.target.result;
// If we are updating we expect the current db value to exist
// Do not confuse a get request succeeding with it actually matching
// something. onsuccess just means completed without error.
if(!old) {
const error = new Error('Cannot find todo to update with title ' + todo.title);
reject(error);
return;
}
// Change old todo object props
old.category = todo.category;
old.foo = todo.bar;
// Replace old with a newer version of itself
store.put(old);
};
});
}
function onpageloadInitStuff() {
mybutton.onclick = handleClick;
}
async function handleClick(event) {
var db;
try {
db = await connect('tododb', 1, upgradeneededfunc);
var newtodo = todolist.querySelector('todolist[checked]');
await updateTodo(db, newTodo);
} catch(error) {
alert(error); // it is ok to alert here, still better to console.log though
} finally {
if(db) {
db.close();
}
}
}
UpdateToDo()
无法进入第二个警报,因为未定义update
,这就是为什么它不会触发第二个警报。我在上面进行了编辑,以提供更大的代码块,以查看我如何进行更新。我用的是光标。然而,我甚至不确定在这一点上我如何更新,因为我甚至无法通过刚刚失败的第一个事务行。再次。。。如果我注释掉第一个事务/存储部分,那么第二个事务将完全启动,因此我假设有某种原因我无法创建第二个事务。我在文档中没有看到任何东西可以帮助meI删除创建第二个事务/存储的行,并将下一行从“newstore.openCursor().onsuccess”更改为使用全局存储“ostore.openCursor().onsuccess”,认为我可以继续使用我先前创建的对象存储。但当我这么做的时候,它就失败了。我也只是在学习如何使用IndexedDB。我还不太清楚,但我知道您必须启动一个新实例,就像为每个请求打开一个新连接一样,您的操作(无论是创建、读取、更新还是删除)都需要是对请求的回调。基本上,先发出请求,然后运行(事件)并处理请求返回的事件。>来自MS Sql Server/ASP.NET后台,打开到同一数据库的多个连接感觉很不直观。--是的,我自己花了很多时间来克服这个事实。可惜的是,除了IndexedDB没有其他选择。WebSQL已被弃用,localStorage/sessionStorage太基础了。我将继续我的研究,稍后再看。我想您可能也想看看它:是另一个IDB包装器。我看过一个很好的教程使用这个。然而,我更喜欢用直截了当的方式去做,直到我感觉足够舒服为止。然后我将继续讨论包装