En sistemas educativos, las páginas de programación de horarios a menudo sufren de problemas de rendimiento debido a grandes volúmenes de datos, lo que puede bloquear el hilo principal del navegador. Este artículo detalla las estrategias aplicadas para mejorar significativamente la velocidad de renderizado de tablas, con enfoque en técnicas de optimización de código y reemplazo de bibliotecas.
Análisis de Rendimiento
Utilizando herramientas de análisis de rendimiento del navegador, se identificaron cuellos de botella en funciones relacionadas con el algoritmo diff de Vue 3. Los datos recopilados mostraron tiempos de renderizado del hilo principal de hasta 8 segundos antes de las optimizaciones.
Implementación de Optimizaciones
Reemplazo de Bibliotecas de Tablas
Se sustituyó la biblioteca arco-design por vxe-table para gestionar el renderizado de tablas. La biblioteca original utilizaba extensivamente ref y computed, lo que generaba re-renderizados innecesarios. La nueva biblioteca mejoró la eficeincia en un 80% al minimizar las actualizaciones del DOM.
Optimización de Algoritmos
Se rediseñó el procesamiento de datos para reducir la complejidad temporal. Originalmente, existían bucles anidados con complejidad O(n³). Mediante la colaboración con el backend, se reestructuró la entrega de datos:
- Una API devuelve datos de clases en formato de mapa para construir encabezados de tabla.
- Otra API proporciona datos de horarios agrupados por clase y fecha.
Esto permitió utilizar búsquedas por clave de mapa, reduciendo la complejidad a O(n²).
Ejemplo de Código Reestructurado
Transformación de datos de columnas:
/**
* Convierte datos de clases en columnas de tabla
* @param classData Datos de clases obtenidos del API
* @returns Arreglo de columnas para la tabla
*/
function generateTableColumns(classData) {
const baseColumn = {
title: 'Fecha',
field: 'date',
fixed: 'left',
width: 140
};
const columns = [baseColumn];
const classMap = new Map();
Object.entries(classData).forEach(([key, value]) => {
const [classId, className] = key.split(',');
const column = {
campusId: classId,
campusName: className,
children: []
};
classMap.set(classId, column);
columns.push(column);
});
classMap.forEach((column, classId) => {
const relatedItems = classData[classId] || [];
relatedItems.forEach(item => {
column.children.push({
data: item,
templateKey: `field_${item.id}`
});
});
});
return columns;
}
Procesamiento de filas de datos:
/**
* Genera datos de filas para la tabla
* @param startDate Fecha de inicio
* @param endDate Fecha de fin
* @param scheduleData Datos de horarios del API
* @returns Datos aplanados y estructurados
*/
function buildRowData(startDate, endDate, scheduleData) {
const rows = [];
let currentDate = new Date(startDate);
while (currentDate <= new Date(endDate)) {
const dateKey = currentDate.toISOString().split('T')[0];
const row = {
date: dateKey,
dayOfWeek: getDayName(currentDate.getDay())
};
rows.push(row);
currentDate.setDate(currentDate.getDate() + 1);
}
Object.entries(scheduleData).forEach(([key, subjects]) => {
const [classId, dateStr] = key.split(',');
const targetRow = rows.find(row => row.date === dateStr);
if (targetRow) {
targetRow[`class_${classId}`] = subjects;
}
});
return { rows, flattened: Object.values(scheduleData).flat() };
}
Optimizaciones Adicionales
- Uso de
shallowRefen lugar derefpara reducir la reactividad profunda. - Aplicación de
Promise.allpara manejar operaciones asíncronas en paralelo. - Implementación de patrones de diseño como Estrategia para gestionar estados y Constructor para objetos complejos.
Resultados
Tras las optimizaciones, el tiempo de renderizado del hilo principal se redujo a aproximadamente 1 segundo. Los bucles de procesamiento de datos se aceleraron en un 50%, y la experinecia de usuario mejoró notablemente en escenarios de alta carga.