在某些功能完成之前触发 OnComplete ( Javascript / IndexedDB )
OnComplete firing before certain function is completed ( Javascript / IndexedDB )
我正在使用 IndexedDB 在我正在开发的应用程序上离线存储数据。我的问题是事务的 OnComplete 在负责存储数据的函数完成之前被触发。我需要知道如何让 OnComplete 等待这个函数在被解雇之前完成它的工作。
这就是我到目前为止所拥有的...函数 populateDatabase 用于存储数据。为此,里面还有另外两个。
function populateDatabase() {
var i = 0;
requestFileSystem(LocalFileSystem.PERSISTENT, 0, obtainDataFile, onError);
try {
if (localDatabase != null && localDatabase.db != null) {
console.log('Started adding records');
var transaction = localDatabase.db.transaction(osTableName, "readwrite");
if (transaction) {
transaction.oncomplete = function(event) {
console.log("transaction completed.");
localDatabase.db.close();
}
transaction.onabort = function(event) {
console.log("transaction aborted.");
localDatabase.db.close();
}
transaction.ontimeout = function(event) {
console.log("transaction timeout.");
localDatabase.db.close();
}
var store = transaction.objectStore(osTableName);
if (data.length > 0)
{
if (store)
addData(transaction, store, data, 0, true);
}
}
console.log('Finished adding records');
}
} catch (e) {
console.log(e.message);
}
}
obtainDataFile,基本上从 txt 文件中读取数据并存储在数据变量中
function obtainDataFile(fileSystem) {
var directoryEntry = fileSystem.root;
directoryEntry.getFile("EstoqueCSV.txt", {
create: true,
exclusive: false
}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend =
function(evt) {
var csv = evt.target.result;
data = $.csv.toObjects(csv);
};
reader.readAsText(file);
}, onError)
}, onError);
}
并且这个递归函数用于循环遍历数据数组,以便一个一个地存储寄存器。
function addData(txn, store, records, i, commitT) {
try {
if (i < records.length) {
var rec = records[i];
var req = store.add(rec);
req.onsuccess = function(ev) {
i++;
console.log("Adding record " + i);
addData(txn, store, records, i, commitT);
}
req.onerror = function(ev) {
console.log("Failed to add record." + " Error: " + ev.message);
}
} else if (i == records.length) {
console.log('Finished adding ' + records.length + " records");
}
} catch (e) {
console.log(e.message);
}
}
问题是我的代码在 addData 函数完成之前到达 transaction.oncomplete。我不确定在这种情况下我应该做什么。一直在找异步调用、回调函数之类的话题,还是没能解决。
在此先感谢您的帮助。
您必须在开始交易前加载所有数据。从您的代码中我看不到 data
已加载。否则,您的代码看起来是正确的。
我已经按照您的方法以更简单的方式缩小了您的问题,正如预期的那样,它的效果很好。
因此,您的方法和代码看起来很干净,但由于您遇到了问题,现在只能通过查看所有代码来确定确切的根本原因。
再想一想,如果在添加数据时出现错误,可以在将数据添加到数据库之前调用 transaction.oncomplete
。因此,观察控制台是否有任何错误,同时添加一个错误处理程序 - transaction.onerror
此外,尝试使用 FOR 循环而不是递归函数。
请注意,iOS 中的 IndexedDB 支持非常有问题,如果是这种情况,那么应该预料到意外。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Whosebug</title>
<script type="text/javascript" charset="utf-8">
var dbDeleteRequest = window.indexedDB.deleteDatabase("toDoList");
dbDeleteRequest.onerror = function(event) {
console.log("Error while deleting database.", true);
};
dbDeleteRequest.onsuccess = function(event) {
// Let us open our database
var DBOpenRequest = window.indexedDB.open("toDoList", 5);
DBOpenRequest.onsuccess = function(event) {
console.log('<li>Database initialised.</li>');
// store the result of opening the database in the db variable. This is used a lot below
db = DBOpenRequest.result;
// Run the addData() function to add the data to the database
addData();
};
DBOpenRequest.onupgradeneeded = function(event) {
console.log('<li>DBOpenRequest.onupgradeneeded</li>');
var db = event.target.result;
db.onerror = function(event) {
console.log('<li>Error loading database.</li>');
};
// Create an objectStore for this database //, { keyPath: "taskTitle" }); { autoIncrement : true }
var objectStore = db.createObjectStore("toDoList", { autoIncrement : true });
// define what data items the objectStore will contain
objectStore.createIndex("hours", "hours", { unique: false });
objectStore.createIndex("minutes", "minutes", { unique: false });
objectStore.createIndex("day", "day", { unique: false });
objectStore.createIndex("month", "month", { unique: false });
objectStore.createIndex("year", "year", { unique: false });
objectStore.createIndex("notified", "notified", { unique: false });
};
};
function addData() {
// Create a new object ready to insert into the IDB
var newItem = [];
newItem.push({ taskTitle: "Walk dog1", hours: 19, minutes: 30, day: 24, month: "December", year: 2013, notified: "no" });
newItem.push({ taskTitle: "Walk dog2", hours: 19, minutes: 30, day: 24, month: "December", year: 2013, notified: "no" });
newItem.push({ taskTitle: "Walk dog3", hours: 19, minutes: 30, day: 24, month: "December", year: 2013, notified: "no" });
console.log(newItem);
// open a read/write db transaction, ready for adding the data
var transaction = db.transaction(["toDoList"], "readwrite");
// report on the success of opening the transaction
transaction.oncomplete = function(event) {
console.log('<li>Transaction completed: database modification finished.</li>' + new Date());
};
transaction.onerror = function(event) {
console.log('<li>Transaction not opened due to error. Duplicate items not allowed.</li>');
};
// create an object store on the transaction
var objectStore = transaction.objectStore("toDoList");
addData2(transaction, objectStore, newItem, 0, true);
};
function addData2(txn, store, records, i, commitT) {
try {
if (i < 10000) {
var rec = records[i];
var req = store.add(rec);
req.onsuccess = function(ev) {
i++;
console.log("Adding record " + i + " " + new Date());
addData2(txn, store, records, i, commitT);
}
req.onerror = function(ev) {
console.log("Failed to add record." + " Error: " + ev.message);
}
} else if (i == records.length) {
console.log('Finished adding ' + records.length + " records");
}
} catch (e) {
console.log(e.message);
}
};
</script>
</head>
<body>
</body>
</html>
For循环方法:
for(var i =0; i < 1000; i++){
// add our newItem object to the object store
var objectStoreRequest = objectStore.add(newItem[0]);
objectStoreRequest.onsuccess = function(event) {
// report the success of our new item going into the database
console.log('<li>New item added to database.</li>' + new Date());
};
}
编辑:根据评论中的讨论
更新您的 populateDatabase
以在调用 requestFileSystem
时添加回调方法。此外,更新您的 requestFileSystem
以接受一个将作为回调的参数,并在最后调用它。我认为您的 requestFileSystem
有一些异步调用,因为该方法甚至在完全完成之前就返回了。
function populateDatabase() {
var i = 0;
requestFileSystem(LocalFileSystem.PERSISTENT, 0, obtainDataFile, onError, function(){
try {
if (localDatabase != null && localDatabase.db != null) {
console.log('Started adding records');
var transaction = localDatabase.db.transaction(osTableName, "readwrite");
if (transaction) {
transaction.oncomplete = function(event) {
console.log("transaction completed.");
localDatabase.db.close();
}
transaction.onabort = function(event) {
console.log("transaction aborted.");
localDatabase.db.close();
}
transaction.ontimeout = function(event) {
console.log("transaction timeout.");
localDatabase.db.close();
}
var store = transaction.objectStore(osTableName);
if (data.length > 0)
{
if (store)
addData(transaction, store, data, 0, true);
}
}
console.log('Finished adding records');
}
} catch (e) {
console.log(e.message);
}
});
}
接受 requestFileSystem
的回调
requestFileSystem(LocalFileSystem.PERSISTENT, 0, obtainDataFile, onError, callback){
//After your asynchronous processing (I am assuming based on your description of problem) is done... Probably you will have some event handler or something, so in the end of that use below call...
if (callback && typeof(callback) == 'function') {
callback(event);
}
}
我正在使用 IndexedDB 在我正在开发的应用程序上离线存储数据。我的问题是事务的 OnComplete 在负责存储数据的函数完成之前被触发。我需要知道如何让 OnComplete 等待这个函数在被解雇之前完成它的工作。
这就是我到目前为止所拥有的...函数 populateDatabase 用于存储数据。为此,里面还有另外两个。
function populateDatabase() {
var i = 0;
requestFileSystem(LocalFileSystem.PERSISTENT, 0, obtainDataFile, onError);
try {
if (localDatabase != null && localDatabase.db != null) {
console.log('Started adding records');
var transaction = localDatabase.db.transaction(osTableName, "readwrite");
if (transaction) {
transaction.oncomplete = function(event) {
console.log("transaction completed.");
localDatabase.db.close();
}
transaction.onabort = function(event) {
console.log("transaction aborted.");
localDatabase.db.close();
}
transaction.ontimeout = function(event) {
console.log("transaction timeout.");
localDatabase.db.close();
}
var store = transaction.objectStore(osTableName);
if (data.length > 0)
{
if (store)
addData(transaction, store, data, 0, true);
}
}
console.log('Finished adding records');
}
} catch (e) {
console.log(e.message);
}
}
obtainDataFile,基本上从 txt 文件中读取数据并存储在数据变量中
function obtainDataFile(fileSystem) {
var directoryEntry = fileSystem.root;
directoryEntry.getFile("EstoqueCSV.txt", {
create: true,
exclusive: false
}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend =
function(evt) {
var csv = evt.target.result;
data = $.csv.toObjects(csv);
};
reader.readAsText(file);
}, onError)
}, onError);
}
并且这个递归函数用于循环遍历数据数组,以便一个一个地存储寄存器。
function addData(txn, store, records, i, commitT) {
try {
if (i < records.length) {
var rec = records[i];
var req = store.add(rec);
req.onsuccess = function(ev) {
i++;
console.log("Adding record " + i);
addData(txn, store, records, i, commitT);
}
req.onerror = function(ev) {
console.log("Failed to add record." + " Error: " + ev.message);
}
} else if (i == records.length) {
console.log('Finished adding ' + records.length + " records");
}
} catch (e) {
console.log(e.message);
}
}
问题是我的代码在 addData 函数完成之前到达 transaction.oncomplete。我不确定在这种情况下我应该做什么。一直在找异步调用、回调函数之类的话题,还是没能解决。
在此先感谢您的帮助。
您必须在开始交易前加载所有数据。从您的代码中我看不到 data
已加载。否则,您的代码看起来是正确的。
我已经按照您的方法以更简单的方式缩小了您的问题,正如预期的那样,它的效果很好。
因此,您的方法和代码看起来很干净,但由于您遇到了问题,现在只能通过查看所有代码来确定确切的根本原因。
再想一想,如果在添加数据时出现错误,可以在将数据添加到数据库之前调用 transaction.oncomplete
。因此,观察控制台是否有任何错误,同时添加一个错误处理程序 - transaction.onerror
此外,尝试使用 FOR 循环而不是递归函数。
请注意,iOS 中的 IndexedDB 支持非常有问题,如果是这种情况,那么应该预料到意外。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Whosebug</title>
<script type="text/javascript" charset="utf-8">
var dbDeleteRequest = window.indexedDB.deleteDatabase("toDoList");
dbDeleteRequest.onerror = function(event) {
console.log("Error while deleting database.", true);
};
dbDeleteRequest.onsuccess = function(event) {
// Let us open our database
var DBOpenRequest = window.indexedDB.open("toDoList", 5);
DBOpenRequest.onsuccess = function(event) {
console.log('<li>Database initialised.</li>');
// store the result of opening the database in the db variable. This is used a lot below
db = DBOpenRequest.result;
// Run the addData() function to add the data to the database
addData();
};
DBOpenRequest.onupgradeneeded = function(event) {
console.log('<li>DBOpenRequest.onupgradeneeded</li>');
var db = event.target.result;
db.onerror = function(event) {
console.log('<li>Error loading database.</li>');
};
// Create an objectStore for this database //, { keyPath: "taskTitle" }); { autoIncrement : true }
var objectStore = db.createObjectStore("toDoList", { autoIncrement : true });
// define what data items the objectStore will contain
objectStore.createIndex("hours", "hours", { unique: false });
objectStore.createIndex("minutes", "minutes", { unique: false });
objectStore.createIndex("day", "day", { unique: false });
objectStore.createIndex("month", "month", { unique: false });
objectStore.createIndex("year", "year", { unique: false });
objectStore.createIndex("notified", "notified", { unique: false });
};
};
function addData() {
// Create a new object ready to insert into the IDB
var newItem = [];
newItem.push({ taskTitle: "Walk dog1", hours: 19, minutes: 30, day: 24, month: "December", year: 2013, notified: "no" });
newItem.push({ taskTitle: "Walk dog2", hours: 19, minutes: 30, day: 24, month: "December", year: 2013, notified: "no" });
newItem.push({ taskTitle: "Walk dog3", hours: 19, minutes: 30, day: 24, month: "December", year: 2013, notified: "no" });
console.log(newItem);
// open a read/write db transaction, ready for adding the data
var transaction = db.transaction(["toDoList"], "readwrite");
// report on the success of opening the transaction
transaction.oncomplete = function(event) {
console.log('<li>Transaction completed: database modification finished.</li>' + new Date());
};
transaction.onerror = function(event) {
console.log('<li>Transaction not opened due to error. Duplicate items not allowed.</li>');
};
// create an object store on the transaction
var objectStore = transaction.objectStore("toDoList");
addData2(transaction, objectStore, newItem, 0, true);
};
function addData2(txn, store, records, i, commitT) {
try {
if (i < 10000) {
var rec = records[i];
var req = store.add(rec);
req.onsuccess = function(ev) {
i++;
console.log("Adding record " + i + " " + new Date());
addData2(txn, store, records, i, commitT);
}
req.onerror = function(ev) {
console.log("Failed to add record." + " Error: " + ev.message);
}
} else if (i == records.length) {
console.log('Finished adding ' + records.length + " records");
}
} catch (e) {
console.log(e.message);
}
};
</script>
</head>
<body>
</body>
</html>
For循环方法:
for(var i =0; i < 1000; i++){
// add our newItem object to the object store
var objectStoreRequest = objectStore.add(newItem[0]);
objectStoreRequest.onsuccess = function(event) {
// report the success of our new item going into the database
console.log('<li>New item added to database.</li>' + new Date());
};
}
编辑:根据评论中的讨论
更新您的 populateDatabase
以在调用 requestFileSystem
时添加回调方法。此外,更新您的 requestFileSystem
以接受一个将作为回调的参数,并在最后调用它。我认为您的 requestFileSystem
有一些异步调用,因为该方法甚至在完全完成之前就返回了。
function populateDatabase() {
var i = 0;
requestFileSystem(LocalFileSystem.PERSISTENT, 0, obtainDataFile, onError, function(){
try {
if (localDatabase != null && localDatabase.db != null) {
console.log('Started adding records');
var transaction = localDatabase.db.transaction(osTableName, "readwrite");
if (transaction) {
transaction.oncomplete = function(event) {
console.log("transaction completed.");
localDatabase.db.close();
}
transaction.onabort = function(event) {
console.log("transaction aborted.");
localDatabase.db.close();
}
transaction.ontimeout = function(event) {
console.log("transaction timeout.");
localDatabase.db.close();
}
var store = transaction.objectStore(osTableName);
if (data.length > 0)
{
if (store)
addData(transaction, store, data, 0, true);
}
}
console.log('Finished adding records');
}
} catch (e) {
console.log(e.message);
}
});
}
接受 requestFileSystem
requestFileSystem(LocalFileSystem.PERSISTENT, 0, obtainDataFile, onError, callback){
//After your asynchronous processing (I am assuming based on your description of problem) is done... Probably you will have some event handler or something, so in the end of that use below call...
if (callback && typeof(callback) == 'function') {
callback(event);
}
}