Google Analytics

martes, 20 de agosto de 2013

Optimiza tus aplicaciones JS con Chrome

Cuando empiezas a trabajar en aplicaciones JavaScript más complejas tienes que tener cuidado con muchos más factores de los que piensas. Los recursos son escasos y al correr en único thread, siempre que no utilices web workers, se pueden producir bloqueos inesperados que no son tan sencillos de encontrar. Pero Chrome nos permite hacer profiling de la aplicación de una manera muy sencilla y os lo mostraré con un caso real con el que me he encontrado.

Dejadme que primero os ponga en situación sobre el ejemplo que usaremos. Tenemos una aplicación móvil multiplataforma que tiene datos almacenados en el local storage, pero siempre que tengamos conexión nos gustaría verificar contra el servidor si hay datos más nuevos o no para que el usuario pueda decidir si quiere actualizarlos. El problema reside en que al llegar a esta pantalla la aplicación tardaba en responder. Después de meses sin tocar la aplicación o incluso si no has trabajado en la misma es complicado saber que puede pasar, por lo que lo único que podemos intuir es que al correr con un único thread hay algún proceso que no ha terminado e impide que la aplicación responda a otros eventos.

Lo que debemos hacer a continuación es arrancar la aplicación con Chrome y activar las herramientas de desarrollo (cmd + alt + i si estás en Mac OS). Personalmente cuando voy a hacer profiling prefiero que las herramientas de desarrollo estén en una ventana separada porque son una gran cantidad de datos.


Vemos como hay una opción que se denomina Profiles, la activamos y veremos una pantalla como la siguiente.


Tan sólo tenemos que hacer click en el botón Start con la opción Collect JavaScript CPU Profile activa y Chrome se pondrá a almacenar los datos del profiling automáticamente mientras navegamos. Cuando hayamos terminado la navegación deseada hacemos click en Stop y podremos analizar los datos mediante diversas representaciones, aunque mi favorita es Flame Chart por que es muy visual y me permite saber de forma más sencilla donde se está utilizando el tiempo de CPU.


Para poder detectar donde se están produciendo los problemas tendremos que conocer un poco nuestro código e ir ampliando las zonas de la gráfica que nos interese, para ello podemos seleccionar secciones en la vista general de forma que nos amplíe los datos en la vista de detalle. En esta vista tendremos la pila de invocaciones de funciones, en donde las funciones invocadas están por encima de las que invocan. Además puedes hacer click en cualquiera de las invocaciones y nos llevará a la parte del código en la que se realiza la llamada, lo cual es muy útil para tener el contexto completo de lo que está haciendo la aplicación.


Por ejemplo en mi caso podemos ver como hay múltiples llamadas a un método denominado getDefectsOfflineData que se están llevando la mayor parte del tiempo de computo. Este método se encarga de recuperar desde el local storage una serie de datos y no se puede optimizar más, pero si hacemos click en el bloque anónimo que lo invoca podemos ver cual es el error.


Después de analizar el código podemos observar como hay una operación muy costosa, como es la recuperación de los datos desde el local storage, que se repite múltiples veces dentro de un bucle. Si extraemos dicha operación de la siguiente manera podemos ver como el tiempo de ejecución pasa de varios segundos a menos de 1/4 de segundo.



Y de esta manera la detección de leaks y código ineficiente, que podría haber sido muy complicado y tedioso, se puede solucionar de una manera bastante sencilla y gráfica.

*Disclaimer*

El código inicial asociado al ejemplo es real, pero la versión modificada no es el código desplegado en producción, no está optimizado ni sigue otros principios como "Clean Code", simplemente porque la intención de este artículo no es hablar de código limpio y mantenible.

"Repito niños", antes de pasar a producción limpiad el código y hacedlo más legible, os compensará en el futuro.


No hay comentarios: