Prohibida la reproducción no autorizada
1. Procesamiento de cálculos costosos
Quizás el aspecto más complejo del desarrollo de aplicaciones Javascript complejas es la naturaleza de un solo subproceso de la interfaz de usuario. La mejor situación cuando Javascript maneja la interacción del usuario es una respuesta lenta, y la peor situación es la falta de respuesta que hace que el navegador se cuelgue (cuando se ejecuta Javascript, todas las operaciones de actualización en la página se suspenden). Debido a este hecho, es imperativo reducir todas las operaciones complejas (cualquier cálculo de más de 100 ms) a un nivel manejable. Además, si el script no se detiene después de ejecutarse durante al menos 5 segundos, algunos navegadores (como Firefox y Opera) generarán un cuadro de aviso para advertir al usuario que el script no responde.
Obviamente, esto no es deseable y producir una interfaz que no responda no es bueno. Sin embargo, es casi seguro que este sea el caso cuando necesita procesar grandes cantidades de datos (como procesar miles de elementos DOM).
En este momento, el cronómetro resulta especialmente útil. Debido a que el temporizador puede pausar efectivamente la ejecución del código Javascript, también puede evitar que el navegador cuelgue el código en ejecución (siempre que el código individual no sea suficiente para provocar que el navegador se cuelgue). Con esto en mente, podemos incorporar cálculos de bucle normales e intensivos en cálculos sin bloqueo. Veamos el siguiente ejemplo donde se requiere este tipo de cálculo.
Una tarea de larga duración:
<tabla><tbody></tbody></table>
// Funcionamiento normal, intensivo
var tabla = document.getElementsByTagName("tbody");
para (var i = 0; i < 2000; i++) {
var tr = document.createElement("tr");
para ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild(document.createTextNode("" + t));
tr.appendChild(td);
}
tabla.appendChild(tr);
}
}
En este ejemplo, creamos un total de 26.000 nodos DOM y completamos los números en una tabla. Esto es demasiado costoso y lo más probable es que cuelgue el navegador e impida la interacción normal del usuario. Podemos introducir temporizadores en esto y obtener resultados diferentes, quizás mejores.
Utilice temporizadores para dividir tareas de larga duración:
<tabla><tbody></tbody></table>
var tabla = document.getElementsByTagName("tbody");
var i = 0, máx = 1999;
setTimeout(función(){
para (var paso = i + 500; i < paso; i++) {
var tr = document.createElement("tr");
para ( var t = 0; t < 6; t++ ){
var td = document.createElement("td");
td.appendChild(document.createTextNode("" + t));
tr.appendChild(td);
}
}
tabla.appendChild(tr);
}
si (yo <máximo)
setTimeout(argumentos.callee, 0);
}, 0);
En nuestro ejemplo modificado, dividimos el cálculo intensivo en cuatro partes, cada una de las cuales crea 6500 nodos. Es poco probable que estos cálculos interrumpan el flujo normal del navegador. El peor de los casos es que estos números se puedan ajustar en cualquier momento (por ejemplo, hacer que varíen entre 250 y 500, de modo que cada una de nuestras celdas genere 3500 nodos DOM). Pero lo más impresionante es cómo cambiamos nuestro código para adaptarlo al nuevo sistema asincrónico. Necesitamos trabajar más para garantizar que los números de los elementos se generen correctamente (el ciclo no termina para siempre). El código es muy similar al nuestro original. Tenga en cuenta que utilizamos cierres para mantener el estado de iteración entre fragmentos de código. Sin cierres, este código sin duda será más complejo.
Hay un claro cambio al utilizar esta tecnología respecto a la original. Los bloqueos prolongados del navegador se reemplazan por 4 actualizaciones visuales de la página. Aunque el navegador intenta ejecutar estos fragmentos de código lo más rápido posible, también muestra cambios DOM (como actualizaciones masivas) después de cada paso del temporizador. En la mayoría de los casos, los usuarios desconocen este tipo de actualizaciones, pero es importante recordar que ocurren.
Hay una situación en la que esta tecnología funcionaría específicamente para mí: una aplicación que creé para calcular los horarios de los estudiantes universitarios. Al principio, la aplicación era CGI típica (el cliente hablaba con el servidor, el servidor calculaba el horario y lo devolvía). Pero lo cambié y puse todos los cálculos de programación en el cliente. Esta es la vista de los cálculos de programación:
Estos cálculos son bastante costosos (es necesario recorrer miles de permutaciones para encontrar la respuesta correcta). Este problema se resuelve dividiendo el cálculo del cronograma en unidades reales (actualizando la interfaz de usuario con la parte completada). Al final, los usuarios entregaron una interfaz de usuario rápida, receptiva y utilizable.
A menudo sorprende lo útil que puede ser la tecnología. Lo encontrará utilizado a menudo en programas de larga ejecución, como cuadros de prueba (lo analizamos al final de este capítulo). Más importante aún, esta tecnología nos muestra lo fácil que es solucionar las limitaciones del entorno del navegador y al mismo tiempo brindar a los usuarios una experiencia rica.