Volver al blog
Optimización de performance en interfaz de gestión de viajes médicos
15 de marzo de 2024
~3 min lectura
Por Emerson Díaz
JavaScriptPerformanceHealthcareFrontendUX
Optimización de performance en interfaz de gestión de viajes médicos
En el desarrollo del sistema de gestión de ambulancias para la CCSS, uno de los mayores retos fue crear una interfaz que manejara eficientemente miles de citas médicas con múltiples filtros y estados en tiempo real.
El problema
La interfaz original tenía problemas significativos de rendimiento:
- Carga lenta: 3+ segundos para mostrar la lista de citas
- UI bloqueante: La búsqueda congelaba la interfaz durante la escritura
- Sincronización compleja: Datos de citas, viajes y relaciones desactualizados
// Código original problemático
function buscarCitas() {
// Búsqueda directa sin debounce - bloqueaba UI
const input = document.getElementById('search').value;
obtenerTodasLasCitas(); // Llamada en cada keystroke
}
La solución
1. Carga paralela de datos
Implementamos Promise.all para cargar múltiples endpoints simultáneamente:
async function obtenerCitas() {
try {
// Carga paralela en lugar de secuencial
const [citas, viajes, relacionesViajesCitas] = await Promise.all([
cargarCitas(),
cargarViajes(),
cargarRelacionesViajesCitas(),
]);
citasCombinadas = combinarCitasYViajes(citas, viajes, relacionesViajesCitas);
mostrarCitas(citasCombinadas);
} catch (error) {
showToast("Error", "Ocurrió un problema al obtener las citas");
}
}
2. Optimización de búsquedas con debouncing
Agregamos debounce para evitar llamadas excesivas:
// Debounce optimizado para búsquedas
document.getElementById("searchTrips")
.addEventListener("keyup", debounce(handleSearchTrips, 300));
function debounce(func, wait) {
let timeout;
return function() {
const context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
3. Gestión inteligente de estado
Utilizamos Map para optimizar búsquedas y Set para tracking de selecciones:
function combinarCitasYViajes(citas, viajes, relaciones) {
// Map para O(1) lookup en lugar de O(n) con arrays
const mapaCitas = new Map();
citas.forEach(cita => {
mapaCitas.set(cita.idCita, cita);
});
// Combinación eficiente de datos relacionales
if (relaciones !== undefined) {
relaciones.forEach(relacion => {
if (mapaCitas.has(relacion.idCita)) {
const cita = mapaCitas.get(relacion.idCita);
const viaje = viajes.find(v => v.idViaje === relacion.idViaje);
if (viaje) {
cita.idUnidad = viaje.idUnidad;
cita.idViaje = relacion.idViaje;
}
}
});
}
return Array.from(mapaCitas.values());
}
Resultados
- Tiempo de carga: De 3.2s a 0.8s (↓75%)
- Responsividad: Búsqueda instantánea sin bloqueo de UI
- Gestión de estado: Sincronización 100% confiable entre datos relacionados
- UX mejorada: Filtros inteligentes que priorizan elementos relevantes
Técnicas clave aplicadas
Optimización de DOM
- Destrucción/recreación eficiente de DataTables
- Event delegation para checkboxes dinámicos
- Lazy rendering de elementos complejos
Manejo de errores robusto
// Interceptor global para tokens expirados
axios.interceptors.response.use(
response => response,
error => {
if (error.response && error.response.status === 401) {
localStorage.removeItem('token');
window.location.href = 'index.html';
}
return Promise.reject(error);
}
);
Validación en tiempo real
function checkcamilla() {
const checkboxes = document.querySelectorAll('.cita-checkbox:checked:not(:disabled)');
let camilla = 0;
checkboxes.forEach(checkbox => {
const row = checkbox.closest('tr');
if (row.dataset.camilla === 'Requerido') {
camilla++;
}
});
if (camilla > 1) {
showToast('Advertencia', 'Ya hay una o más citas que requieren camilla');
}
return true;
}
Lecciones aprendidas
- Carga paralela: Promise.all puede reducir drásticamente tiempos de carga inicial
- Debouncing es crítico: En interfaces con búsqueda frecuente, evita sobrecargar el sistema
- Estructuras de datos importan: Map vs Array puede marcar la diferencia en performance
- Estado centralizado: Un buen manejo de estado previene bugs complejos en interfaces dinámicas
Esta optimización permitió que el personal médico gestionara hasta 500+ citas simultáneas con una experiencia de usuario fluida y confiable.