Синхронный запрос к базе данных Web SQL
Я работаю над JavaScript, который взаимодействует с клиентской базой данных SQLite через новые window.openDatabase(...)
, database.transaction(...)
и связанные с ними API. Поскольку большинство из вас знает, когда вы выполняете запрос таким образом, это асинхронный вызов, который обычно хорош. Вы можете сделать вызов и обработать результаты, когда это необходимо, с помощью обратных вызовов.
В моей текущей ситуации я работаю над algo для клиента, который выполняет некоторую иерархию, идущую в локально сохраненной базе данных. У части алгоритма, с которым у меня возникают проблемы, нужно начинать с некоторой строки, которая имеет ссылку на "родительский" (по id), который является еще одной строкой далее в таблице. Я должен продолжать идти по этому дереву, пока не дойду до корня.
Проблема в том, что я нахожусь в точке, где я не уверен, как использовать запрос асинхронного стиля с обратным вызовом, чтобы поддерживать кормление родительских идентификаторов цикла. В идеале я мог бы запросить блокировку, чтобы я мог сделать все это в цикле. Здесь ключевые части моей текущей настройки:
for (i in search.searchResults.resultsArray)
{
hierarchyArr = new Array();
pageHierarchyArr = new Array();
id = search.searchResults.resultsArray[i].ID;
while (id != null && id != "")
{
var hierarchySql = "SELECT ID, parentID, type, content FROM content WHERE ID = " + id;
// This is a prettied up call to database.transaction(...)
var rs = db.getRS(hierarchySql);
// Ideally the code below doesn't execute until rs is populated
hierarchyArr.push(rs[0]);
if (rs[0].type == "page")
{
pageHierarchyArr.push(rs[0]);
// Do some additional work
}
id = rs[0].parentID;
}
}
Как вы можете себе представить, это плохо работает. hierarchyArr получает в него "undefined", а затем script сбой, когда он пытается проверить тип rs [0].
Когда я пытаюсь настроить его с обратным вызовом (db.getRSAndCallback(sql, callbackFunc)
, который я использовал для более ранних, не взаимозависимых запросов, просто отлично), это хуже: внутренний цикл взлетает как сумасшедший, потому что идентификатор не обновляется; предположительно потому, что цикл сохраняет интерпретатор JavaScript настолько занятым, что он никогда не заполняет rs
. В некоторых искусственных испытаниях, где я заставил внутренний цикл сломаться после нескольких итераций, все обратные вызовы начали проходить через все в конце, после завершения цикла.
"Стандарт" (например, сейчас) на http://dev.w3.org/html5/webdatabase/#synchronous-database-api, кажется, указывает на наличие синхронного API, но Я не видел никаких признаков этого в каких-либо браузерах на основе WebKit.
Кто-нибудь может предложить предложения о том, как я могу: a. правильно сформулировать эти итеративные взаимозависимые запросы с помощью обратных вызовов или, b. каким-то образом получить вызов на самом деле происходит синхронно или, по-видимому, синхронно.
Большое спасибо заранее всем, кто взломал эту, казалось бы, сложную небольшую проблему.
Наим
P.S. Здесь клиентская реализация db.getRS
для справки:
.
.
.
getRS: function(sql)
{
var output = [];
db.database.transaction(function(tx)
{
tx.executeSql(sql, [], function(tx,rs)
{
for(i = 0; i < rs.rows.length; i++)
{
output.push(rs.rows.item(i));
}
},
function(tx, error) { ... }
)});
return output;
},
.
.
.
Ответы
Ответ 1
Я использовал обратные вызовы и закрытие для решения аналогичной проблемы, рассмотрим:
function getFolder(id, callback) {
var data = [];
ldb.transaction(function (tx) {
tx.executeSql('SELECT * FROM folders where id=?',
[id],
function (tx, results) {
if (results.rows && results.rows.length) {
for (i = 0; i < results.rows.length; i++) {
data.push(results.rows.item(i));
}
}
if (typeof(callback) == 'function')
callback(data);
},
function (tx, error) {
console.log(error);
});
});
}
В продолжении этого примера папка имеет свойство parent, чтобы определить ее отношение к другим папкам. Как и документ. Следующее предоставит вам путь к документу, используя закрытие (успех):
function getDocPath(doc, callback) {
var path = [];
var parent = doc.parent;
var success = function(folder) {
var folder = folder[0];
parent = folder.parent;
path.push({'id':folder.id,'name':folder.name});
if (parent != "undefined")
getFolder(parent, success);
else
if ( typeof(callback) == 'function' ) callback(path.reverse());
}
getFolder(parent, success);
}
Ответ 2
Вы можете использовать обратные вызовы с закрытием в свой стек оставшихся запросов. Или вы можете использовать рекурсию, передав стек в качестве параметров.