Información sobre tu app web
Las aplicaciones web de alto rendimiento son fundamentales para una excelente experiencia del usuario. A medida que las aplicaciones web se vuelven cada vez más complejas, comprender el impacto en el rendimiento es fundamental para crear una experiencia atractiva. En los últimos años, aparecieron varias APIs diferentes en el navegador para ayudar a analizar el rendimiento de la red, los tiempos de carga, etcétera, pero no necesariamente brindan detalles detallados con la flexibilidad suficiente para encontrar qué ralentiza tu aplicación. Ingresa la API de Tiempos de usuario, que proporciona un mecanismo que puedes usar para instrumentar tu aplicación web y, así, identificar en qué se emplea el tiempo de tu aplicación. En este artículo, abordaremos la API y algunos ejemplos de cómo usarla.
No puedes optimizar lo que no puedes medir
El primer paso para acelerar una aplicación web lenta es averiguar dónde se está dedicando el tiempo. Medir el impacto en el tiempo de las áreas de código de JavaScript es la forma ideal de identificar los puntos críticos, que es el primer paso para encontrar cómo mejorar el rendimiento. Afortunadamente, la API de Tiempos de usuario proporciona una forma de insertar llamadas a la API en diferentes partes de tu JavaScript y, luego, extraer datos de tiempo detallados que se pueden usar para ayudarte a optimizar.
Tiempo y now() de alta resolución
Una parte fundamental de la medición precisa del tiempo es la precisión. En el pasado, teníamos un tiempo basado en la medición de milisegundos, lo que está bien, pero crear un sitio de 60 FPS sin tirones significa que cada fotograma debe dibujarse en 16 ms. Por lo tanto, cuando solo tienes una precisión de milisegundos, carece de la precisión necesaria para un buen análisis. Ingresa High Resolution Time, un nuevo tipo de tiempo integrado en los navegadores modernos. High Resolution Time nos brinda marcas de tiempo de punto flotante que pueden tener una precisión de microsegundos, mil veces mejor que antes.
Para obtener la hora actual en tu aplicación web, llama al método now(), que forma una extensión de la interfaz Performance. En el siguiente código, se muestra cómo hacerlo:
var myTime = window.performance.now();
Existe otra interfaz llamada PerformanceTiming que proporciona una serie de tiempos diferentes relacionados con la forma en que se carga tu aplicación web. El método now() devuelve el tiempo transcurrido desde que se produjo el tiempo navigationStart en PerformanceTiming.
El tipo DOMHighResTimeStamp
En el pasado, cuando intentabas medir el tiempo de las aplicaciones web, usabas algo como Date.now(), que devuelve un DOMTimeStamp. DOMTimeStamp devuelve un número entero de milisegundos como su valor. Para proporcionar la mayor precisión necesaria para el tiempo de alta resolución, se introdujo un nuevo tipo llamado DOMHighResTimeStamp. Este tipo es un valor de punto flotante que también devuelve la hora en milisegundos. Sin embargo, como es un punto flotante, el valor puede representar milisegundos fraccionarios y, por lo tanto, puede producir una precisión de una milésima de milisegundo.
La interfaz de Tiempos de usuario
Ahora que tenemos marcas de tiempo de alta resolución, usemos la interfaz de Tiempos de usuario para extraer información de tiempo.
La interfaz de Tiempos de usuario proporciona funciones que nos permiten llamar a métodos en diferentes lugares de nuestra aplicación que pueden proporcionar un rastro de migas de pan al estilo de Hansel y Gretel para que podamos hacer un seguimiento de dónde se dedica el tiempo.
Usa mark()
El método mark() es la herramienta principal de nuestro kit de herramientas de análisis de tiempos. Lo que hace mark() es almacenar una marca de tiempo para nosotros. Lo que es muy útil de mark() es que podemos nombrar la marca de tiempo, y la API recordará el nombre y la marca de tiempo como una sola unidad.
Llamar a mark() en varios lugares de tu aplicación te permite calcular cuánto tiempo tardaste en alcanzar esa "marca" en tu aplicación web.
La especificación indica una serie de nombres sugeridos para las marcas que podrían ser interesantes y que se explican por sí mismas, como mark_fully_loaded, mark_fully_visible,mark_above_the_fold, etcétera.
Por ejemplo, podemos establecer una marca para cuando la aplicación se cargue por completo con el siguiente código:
window.performance.mark('mark_fully_loaded');
Si establecemos marcas con nombre en toda nuestra aplicación web, podemos recopilar una gran cantidad de datos de tiempo y analizarlos cuando queramos para determinar qué hace la aplicación y cuándo.
Calcula mediciones con measure()
Una vez que hayas establecido varias marcas de tiempo, querrás averiguar el tiempo transcurrido entre ellas. Para ello, usa el método measure().
El método measure() calcula el tiempo transcurrido entre las marcas y también puede medir el tiempo entre tu marca y cualquiera de los nombres de eventos conocidos en la interfaz PerformanceTiming.
Por ejemplo, puedes calcular el tiempo desde que se completa el DOM hasta que el estado de tu aplicación se carga por completo con un código como el siguiente:
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
Cuando llamas a measure(), se almacena el resultado independientemente de las marcas que establezcas, por lo que puedes recuperarlas más tarde. Si almacenas los tiempos mientras se ejecuta la aplicación, esta sigue respondiendo y puedes volcar todos los datos después de que la aplicación haya terminado de trabajar para que se puedan analizar más tarde.
Se descartan las marcas con clearMarks()
A veces, es útil poder deshacerse de un grupo de marcas que configuraste. Por ejemplo, puedes ejecutar lotes en tu aplicación web y, por lo tanto, quieres comenzar de cero en cada ejecución.
Es bastante fácil deshacerse de cualquier marca que hayas configurado llamando a clearMarks().
Por lo tanto, el siguiente código de ejemplo borraría todas las marcas existentes que tengas para que puedas volver a configurar una ejecución de tiempo si lo deseas.
window.performance.clearMarks();
Por supuesto, hay algunas situaciones en las que tal vez no quieras borrar todas tus marcas. Por lo tanto, si quieres deshacerte de marcas específicas, puedes pasar el nombre de la marca que quieres quitar. Por ejemplo, el siguiente código:
window.performance.clearMarks('mark_fully_loaded');
elimina la marca que establecimos en el primer ejemplo, pero deja sin cambios las demás marcas que establecimos.
También puedes deshacerte de las mediciones que hayas realizado. Para ello, existe un método correspondiente llamado clearMeasures(). Funciona exactamente igual que clearMarks(), pero se aplica a las mediciones que hayas realizado. Por ejemplo, el código:
window.performance.clearMeasures('measure_load_from_dom');
quitará la medición que hicimos en el ejemplo de measure() anterior. Si quieres quitar todas las mediciones, funciona igual que clearMarks(), ya que solo llamas a clearMeasures() sin argumentos.
Cómo obtener los datos de tiempo
Está muy bien establecer marcas y medir intervalos, pero en algún momento querrás obtener esos datos de tiempo para realizar un análisis. Esto también es muy sencillo: solo tienes que usar la interfaz PerformanceTimeline.
Por ejemplo, el método getEntriesByType() nos permite obtener todos nuestros tiempos de marca o todos nuestros tiempos de medición como una lista para que podamos iterar sobre ella y asimilar los datos. Lo bueno es que la lista se devuelve en orden cronológico, por lo que puedes ver las marcas en el orden en que se alcanzaron en tu aplicación web.
El código que se muestra a continuación hace lo siguiente:
var items = window.performance.getEntriesByType('mark');
nos devuelve una lista de todas las marcas que se alcanzaron en nuestra aplicación web, mientras que el código:
var items = window.performance.getEntriesByType('measure');
nos devuelve una lista de todas las mediciones que realizamos.
También puedes obtener una lista de entradas con el nombre específico que les hayas asignado. Por ejemplo, el código:
var items = window.performance.getEntriesByName('mark_fully_loaded');
nos devolvería una lista con un elemento que contiene la marca de tiempo “mark_fully_loaded” en la propiedad startTime.
Medición del tiempo de una solicitud XHR (ejemplo)
Ahora que tenemos una idea clara de la API de User Timing, podemos usarla para analizar cuánto tardan todas nuestras XMLHttpRequests en nuestra aplicación web.
Primero, modificaremos todas nuestras solicitudes send() para emitir una llamada a función que configure las marcas y, al mismo tiempo, cambiaremos nuestras devoluciones de llamada exitosas con una llamada a función que establezca otra marca y, luego, genere una medición de cuánto tardó la solicitud.
Por lo general, nuestro XMLHttpRequest se vería de la siguiente manera:
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
do_something(e.responseText);
}
myReq.send();
En nuestro ejemplo, agregaremos un contador global para hacer un seguimiento de la cantidad de solicitudes y también para usarlo para almacenar una medición de cada solicitud que se realice. El código para hacerlo se ve de la siguiente manera:
var reqCnt = 0;
var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
window.performance.mark('mark_end_xhr');
reqCnt++;
window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();
El código anterior genera una medición con un valor de nombre único para cada XMLHttpRequest que enviamos. Suponemos que las solicitudes se ejecutan en secuencia; el código para las solicitudes paralelas tendría que ser un poco más complejo para controlar las solicitudes que se devuelven fuera de orden, lo dejaremos como un ejercicio para el lector.
Una vez que la aplicación web haya realizado varias solicitudes, podemos volcarlas todas en la consola con el siguiente código:
var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
var req = items[i];
console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}
Conclusión
La API de Tiempos de usuario te brinda muchas herramientas excelentes para aplicar a cualquier aspecto de tu aplicación web. Para reducir los puntos de acceso de tu aplicación, puedes distribuir llamadas a la API en toda tu aplicación web y procesar posteriormente los datos de tiempo generados para crear una imagen clara de dónde se dedica el tiempo. ¿Pero qué sucede si tu navegador no admite esta API? No hay problema, puedes encontrar un polyfill excelente aquí que emula la API muy bien y funciona de manera correcta con webpagetest.org. ¿Qué está esperando? Prueba la API de Tiempos de usuario en tus aplicaciones ahora. Descubrirás cómo acelerarlas y tus usuarios te agradecerán por mejorar su experiencia.