У меня есть процесс инициализации для веб-приложения, которое рекурсивно выполняет запросы WebSQL.
Он включает в себя массив с именем actions
, и к этому массиву добавляются несколько функций. Каждая функция возвращает обещание, которое разрешается при выполнении запроса WebSQL. Большинство из этих функций включают проверку наличия в таблице всех столбцов, которые она должна иметь, и, если нет, удаление таблицы и воссоздание ее с правильной конфигурацией столбцов. (Данные пользователя хранятся на стороне сервера, поэтому при следующем входе в систему таблицы будут заполнены.)
Каждая функция в массиве должна завершиться до того, как начнется следующая. Базовая основа каждой функции в массиве actions
такова:
actions.push(function() {
var d = $q.defer();
Database.recreateTable(table).then(function() {
d.resolve("Success");
}, function(e) { d.resolve(e);});
return d.promise
})
(Строка, которая разрешается даже в случае сбоя функции базы данных, служит для проверки выполнения последующих таблиц.)
Database.recreateTable
- это функция в службе Angular:
var recreateTable = function(table) {
var def = $q.defer();
execute("DROP TABLE IF EXISTS " + table).then(function() {
createTable(table).then(function() {
def.resolve();
}, function(error) {
ValidatorService.log(getScriptName(), error);
def.reject(error);
});
}, function (error) {
ValidatorService.log(getScriptName(), error);
def.reject(error);
});
return def.promise;
}
, где createTable
- это просто следующее:
var createTable = function(table) {
var def = $q.defer();
var q = "CREATE TABLE IF NOT EXISTS " + table + " (" + getColumns(table, true, true) + ")";
execute(q).then(function(s) {
def.resolve();
}, function (error) {
def.reject(error);
});
return def.promise;
}
и execute
- это оболочка для транзакций WebSQL, которая охватывает как веб-использование, так и использование Cordova:
var execute = function (query, bindings) {
bindings = typeof bindings !== 'undefined' && typeof bindings !== 'null' ? bindings : [];
var deferred = $q.defer();
if (db === undefined || db === null) { //initialize first if hasn't been done yet
init().then(executeQuery(), function(error) {} );
}
else {
executeQuery();
}
function executeQuery() {
if (window.cordova) {
$cordovaSQLite.execute(db, query, bindings).then(function (result) {
deferred.resolve(result);
}, function (fail) {
ValidatorService.log(getScriptName(), JSON.stringify(fail));
deferred.reject(fail);
});
}
else {
db = window.openDatabase("database.db", '1.0', 'auto', 1024 * 1024 * 100);
db.transaction(function(tx) {
tx.executeSql(query, bindings, function (tx, result) {
deferred.resolve(result);
}, function (tx, fail) {
deferred.resolve(fail);
});
});
}
}
return deferred.promise;
}
Все функции в массиве actions
выполняются одна за другой со следующим кодом:
function executeRun() {
var d = $q.defer();
function multi(i) {
if (actions.length > 0 && i < actions.length) {
actions[i]().then(function(s) {
multi(i+1);
}, function(e) {
multi(i+1);
})
}
else {
d.resolve();
}
}
multi(0);
return d.promise;
}
В данный момент написано, чтобы продолжить, независимо от того, успешно ли выполнено действие, так что последующие таблицы все равно проверяются, несмотря ни на что. Действия выполняются одно за другим, а не асинхронно, потому что некоторые действия могут быть или не быть добавлены в зависимости от более ранних записей в массиве actions
.
Идея, стоящая за этим, кажется довольно простой, но проблема в том, что после нескольких итераций в цикле запрос просто зависает и не возвращает ответ, поэтому никогда не запускаются обратные вызовы об успешном завершении и об ошибке. Кажется, что не существует какой-либо рифмы или причины, по которой это происходит в тот момент, когда это происходит, и это происходит только в iOS Cordova, когда другие процессы, которые зависят от этих таблиц, возвращают ошибки «таких таблиц нет». В Android Cordova такой проблемы нет.
Я видел, как это происходило в Chrome для настольных компьютеров раньше, оно не остановится даже после нажатия кнопки «Очистить данные сайта». Единственное, что исправило это, это переустановка Chrome.