Контекст
Для системы есть процесс, синхронизирующий информацию из внешнего API (всего 6 таблиц) с помощью транзакций с Web SQL, этот процесс делается вручную с помощью кнопки SINCRONIZAR
и пока процесс работает необходимо предотвратить их вход в систему или повторно синхронизируйте их, чтобы обе кнопки были заблокированы:
Фактический процесс
Я попытался закомментировать нерелевантные части, чтобы упростить понимание.
Используя setInterval() и clearInterval() , мне каким-то образом удалось дождаться завершения нескольких асинхронных событий:
// URLs para consumir cada tabla del API externo
// baseAPI viene desde otro archivo
var cultivosAPI = baseAPI + "/api/cultivos/";
var usuariosAPI = baseAPI + "/api/usuarios/";
var terminalesAPI = baseAPI + "/api/terminales/";
var personalAPI = baseAPI + "/api/personal/";
var laboresAPI = baseAPI + "/api/labores/";
var plantasAPI = baseAPI + "/api/plantas/";
// Objeto para saber el estado de la sincronización de cada
// tabla
var updateStates = {};
// ID inicial del intervalo usado en la función setInterval()
var intervalId = 0;
$(document).ready(function(){
// ...
// Boton ACTUALIZAR, antes de sincronizar se asegura
// de que exista conexión con el servidor
$("#updateBtn").on("click", testConnection);
// ...
});
function testConnection() {
$.ajax(
baseAPI
).done(function (data) {
// Si todo está bien, sincronizar las tablas
updateTables();
}).fail(function() {
// ...
});
}
function updateTables() {
// ...
// Hash para conocer el resultado de actualización de cada tabla,
// es la variable definidida arriba
updateStates = {
"cultivo": null,
"labor": null,
"personal": null,
"planta": null,
"terminal": null,
"usuario": null
};
// Deshabilitar botones
$("#loginBtn").prop("disabled", true);
$("#updateBtn").prop("disabled", true);
// ...
// ***************************************************
// Esta es la parte asíncrona en donde se llama el API
// de cada tabla
// ***************************************************
// Insertar cultivos
$.getJSON(cultivosAPI, {
format: "json"
}).done(function (data) {
db.transaction(function(tx) {
// SQL y otras cosas
});
}).fail(function(data) {
// Marcamos la tabla como incompleta
updateStates["cultivo"] = false;
// ...
});
// Insertar personal
$.getJSON(personalAPI, {
format: "json"
}).done(function (data) {
db.transaction(function(tx) {
// SQL y otras cosas
});
}).fail(function(data) {
// Marcamos la tabla como incompleta
updateStates["personal"] = false;
// ...
});
// Insertar terminales
$.getJSON(terminalesAPI, {
format: "json"
}).done(function (data) {
db.transaction(function(tx) {
// SQL y otras cosas
});
}).fail(function(data) {
// Marcamos la tabla como incompleta
updateStates["terminal"] = false;
// ...
});
// Insertar usuarios
$.getJSON(usuariosAPI, {
format: "json"
}).done(function (data) {
db.transaction(function(tx) {
// SQL y otras cosas
});
}).fail(function(data) {
// Marcamos la tabla como incompleta
updateStates["usuario"] = false;
// ...
});
// Insertar labores
$.getJSON(laboresAPI, {
format: "json"
}).done(function (data) {
db.transaction(function(tx) {
// SQL y otras cosas
});
}).fail(function(data) {
// Marcamos la tabla como incompleta
updateStates["labor"] = false;
// ...
});
// Insertar plantas
$.getJSON(plantasAPI, {
format: "json"
}).done(function (data) {
db.transaction(function(tx) {
// SQL y otras cosas
});
}).fail(function(data) {
// Marcamos la tabla como incompleta
updateStates["planta"] = false;
// ...
});
// Esperar que finalicen las actualizaciones para habilitar
// los botones, valida cada segundo
intervalId = setInterval(updateIsFinished, 1000);
}
function updateIsFinished() {
// El proceso puede haber terminado sin terminar de actualizar por algún
// error encontrado
var updated = true;
var finished = true;
// Iteramos cada estado de la tabla, si la tabla tiene un valor
// false es porque hubo un error en la llamada AJAX, si tiene un
// valor null es porque el AJAX aun no finaliza
for (table in updateStates) {
if (updateStates[table] == false) {
updated = false;
}
if (updateStates[table] == null) {
finished = false;
}
}
if (updated || finished) {
// Limpiar el intervalo
clearInterval(intervalId);
// Resetear valores globales
updateStates = {};
intervalId = 0;
// Habilitar botones
if (updated) {
$("#loginBtn").prop("disabled", false);
$("#updateBtn").prop("disabled", false);
} else if (finished) {
$("#updateBtn").prop("disabled", false);
}
}
}
Спросить
Хотя это работает, я чувствую, что может быть лучший способ добиться этого без необходимости проверять каждую секунду. Я пытался использовать jQuery.when() , но это не сработало.
Как я могу ждать асинхронных событий, не проверяя каждый определенный интервал времени?
Если вы используете jQuery, лучше всего использовать
$.when
.Функция
when
получает список объектов Promise и возвращает другой Promise , который будет разрешен при разрешении каждого из элементов. Будучи обещанием , вы можете связать методыdone
, какfail
обычно.Пример:
В этом случае
done
он выполняется, если все запросы были успешными и хотя бы один из них не удался.fail
Для вашей конкретной проблемы и после небольшого рефакторинга :) я бы попытался решить ее примерно так:
Если код для каждой конечной точки в каждом случае разный, то вы можете поместить его в массив конечных точек :
а потом
Одним из решений, которое приходит на ум, является использование Ajaxstart и Ajaxstop jQuery, которые сообщают вам, когда запрос выполняется и когда он завершен. Для вашего кода это будет примерно так:
При этом вы будете знать, когда запросы будут готовы и кнопки для входа будут отпущены. Со своей стороны, я использовал его только для выполнения 1 запроса, а не нескольких, но я думаю, что он все еще может работать, или самое большее, что вам нужно изменить, это сделать запросы вложенными.