<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrés Estévez</title>
    <description>The latest articles on DEV Community by Andrés Estévez (@andres_aec).</description>
    <link>https://dev.to/andres_aec</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F247939%2Fd602df0e-cf04-4619-b148-60497381324f.jpg</url>
      <title>DEV Community: Andrés Estévez</title>
      <link>https://dev.to/andres_aec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andres_aec"/>
    <language>en</language>
    <item>
      <title>Cómo medir el rendimiento en NodeJS</title>
      <dc:creator>Andrés Estévez</dc:creator>
      <pubDate>Sat, 11 Apr 2020 15:57:02 +0000</pubDate>
      <link>https://dev.to/andres_aec/como-medir-el-rendimiento-con-nodejs-5c2k</link>
      <guid>https://dev.to/andres_aec/como-medir-el-rendimiento-con-nodejs-5c2k</guid>
      <description>&lt;p&gt;En un &lt;a href="https://dev.to/andres_aec/complejidad-algoritmica-o-como-mejorar-el-tiempo-de-ejecucion-3hfc"&gt;post anterior&lt;/a&gt; se explicaba cómo se puede mejorar el rendimiento de una aplicación sin necesidad de reimplementarla en otro lenguaje más rápido. La propuesta consistía en refactorizarla usando otros tipos de datos y algoritmos que proporcionasen un mayor rendimiento.&lt;/p&gt;

&lt;p&gt;Ahora bien, ¿cómo detectamos y decidimos que debemos reimplementar una parte de nuestro código? Por una sospecha. Intuimos que alguna parte de nuestro código es la que está limitando el tiempo de ejecución total de la aplicación, así que es ahí donde debemos actuar. Sin embargo, esta intuición puede ser errónea, y la mejora de rendimiento puede no compensar el tiempo que dediquemos a reimplemetar esta parte del código. Por tanto, antes de reimplementar nada, verifiquemos que nuestra intuición es acertada. Es decir, midamos cuánto tiempo tarda en ejecutarse esa parte del código y comparémoslo con el tiempo total. Si supone un porcentaje significativo entonces estaremos ante un fragmento de código donde merece la pena dedicar esfuerzo a mejorar el rendimiento.&lt;/p&gt;

&lt;h1&gt;
  
  
  Midiendo el tiempo en NodeJS
&lt;/h1&gt;

&lt;p&gt;En NodeJS existen varios mecanismos para medir el tiempo de ejecución. Algunos de ellos se caracterizar por obligar al programador a indicar cuáles son las zonas de código a medir, como &lt;a href="https://nodejs.org/api/console.html#console_console_time_label" rel="noopener noreferrer"&gt;&lt;code&gt;console.time&lt;/code&gt;&lt;/a&gt; o la &lt;a href="https://nodejs.org/api/perf_hooks.html" rel="noopener noreferrer"&gt;&lt;code&gt;Performance Timing API&lt;/code&gt;&lt;/a&gt;. Otra aproximación es el &lt;code&gt;profiling&lt;/code&gt;, o análisis de rendimiento en tiempo de ejecución. Veremos que una aplicación &lt;code&gt;NodeJS&lt;/code&gt; se puede ejecutar en modo &lt;code&gt;profiling&lt;/code&gt; y, al finalizar, se genera automáticamente un informe con los tiempos de ejecución de cada función. La interpretación de este informe puede ser un tanto tediosa y difícil, por lo que se han desarrollado herramientas visuales que ayuda a su interpretación, como &lt;a href="https://clinicjs.org/" rel="noopener noreferrer"&gt;&lt;code&gt;clinicjs&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A continuación explico cada uno de los métodos usando el siguiente código como ejemplo. Se trata de una funcíon &lt;code&gt;slowFunc&lt;/code&gt; que llama a otras dos, &lt;code&gt;add&lt;/code&gt; y &lt;code&gt;div&lt;/code&gt;. Al ejecutarlo nos daremos cuenta de que hay un cierto retardo, cuando el código debería ser inmediato, ya que realiza simplemente una suma y una división. Veamos cómo depurar el rendimiento.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// code to consume CPU cycles&lt;/span&gt;
      &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slowFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;slowFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  console.time
&lt;/h2&gt;

&lt;p&gt;Con esta herramienta podemos medir el tiempo de ejecución entre dos puntos de nuestro código. El primero será aquel en el que escribimos &lt;code&gt;console.time(&amp;lt;etiqueta&amp;gt;)&lt;/code&gt;, y el segundo &lt;code&gt;console.timeEnd(&amp;lt;etiqueta&amp;gt;)&lt;/code&gt;. Los instantes de paso se grabarán de manera transparente y, en la terminal veremos cómo se escribe el tiempo transcurrido entre ambos. Para nuestro código de ejemplo, tendríamos:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// code to consume CPU cycles&lt;/span&gt;
      &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slowFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slowFunc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slowFunc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;slowFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;En la terminal aparecerá:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

div: 1000.220ms
slowFunc: 1002.300ms


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Observamos lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;es posible poner un bloque &lt;code&gt;time... timeEnd&lt;/code&gt; dentro de otro&lt;/li&gt;
&lt;li&gt;la etiqueta que pusimos en el código, &lt;code&gt;div&lt;/code&gt; y &lt;code&gt;slowFunc&lt;/code&gt; se usan para identificar en la terminal cada uno de los tiempos medidos.&lt;/li&gt;
&lt;li&gt;se observa que hay una fragmento del código que ocupa casi todo el tiempo total. En este caso, el código del &lt;code&gt;div&lt;/code&gt; representa casi el total de &lt;code&gt;slowFunc&lt;/code&gt;. Por tanto este será el código a refactorizar para mejorar su eficiencia.&lt;/li&gt;
&lt;li&gt;se trata de un mecanismo invasivo, ya que es necesario introducir líneas de código en el propio código que queremos probar&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance API
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NodeJS&lt;/code&gt; proporciona una interfaz de menor nivel para medir el rendimiento, que permite realizar cálculos más sofisticados y dar más control al desarrollador. Se trata de una API bastante amplia, por lo que en este post nos ceñiremos a lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;medir el tiempo entre dos puntos del código&lt;/li&gt;
&lt;li&gt;medir el tiempo de ejecución de una función &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tiempo entre dos puntos del código
&lt;/h3&gt;

&lt;p&gt;Para esta tarea se realizará un proceso similar al explicado en &lt;code&gt;console.time&lt;/code&gt;: indicaremos el principio y final del bloque de código que queremos medir:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

   &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;inicio&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;código&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;medir&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;fin&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;La primera diferencia con el mecanismo anterior viene ahora: el valor medido no aparece automáticamente en pantalla. Para obtenerlo es necesario que lo pidamos explícitamente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

   &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;inicio&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;código&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;medir&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;fin&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;la&lt;/span&gt; &lt;span class="nx"&gt;medición&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;inicio&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;etiqueta&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="nx"&gt;fin&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;¿Y dónde aparece el valor medido? La API proporciona un mecanismo para monitorizar las mediciones realizadas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PerformanceObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;entryTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;measure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Lo cuál escribiría en pantalla lo siguiente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;PerformanceEntry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slowFunc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;entryType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;measure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;36.153894&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;999.870955&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="nx"&gt;PerformanceEntry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;entryType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;measure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;36.186445&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;999.804569&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notad cómo este mecanismo es mucho más potente que el &lt;code&gt;console.time&lt;/code&gt; ya que nos permite gestionar por código las mediciones. Es decir, podemos recoger los valores medidos, almacenarlos, procesarlos, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tiempo de ejecución de una función
&lt;/h3&gt;

&lt;p&gt;Otro mecanismo que nos ofrece la &lt;code&gt;Performance API&lt;/code&gt; es &lt;code&gt;timerify&lt;/code&gt;. Se trata de sustituir la llamada de la función a medir por un &lt;code&gt;wrapper&lt;/code&gt; que incorpora mediciones de rendimiento. Así, donde antes teníamos una llamada a &lt;code&gt;dummy()&lt;/code&gt;, ahora llamaremos a otra función, llamémosla &lt;code&gt;dummy_timerify&lt;/code&gt;, que abremos obtenido de la siguiente forma:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dummy_timerify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timerify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dummy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para la obtención de los resultados del análisis usamos el mismo mecanismo basado en &lt;code&gt;callbacks&lt;/code&gt; visto en el punto anterior. Nuestro código de ejemplo quedaría de la siguiente manera:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PerformanceObserver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;perf_hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PerformanceObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntries&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="c1"&gt;//performance.clearMarks();&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;entryTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// code to consume CPU cycles&lt;/span&gt;
   &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slowFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;div_timerify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div_timerify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timerify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;slowFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notemos lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a la función &lt;code&gt;observe&lt;/code&gt; hay que pasarle &lt;code&gt;function&lt;/code&gt;, como &lt;code&gt;entryType&lt;/code&gt;, en lugar de &lt;code&gt;measure&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;se trata de un mecanismo invasivo. Otra vez es necesario añadir código a propósito de la medición. Sin embargo, a diferencia de los anteriores, el impacto es menor ya que solo es necesario modificar la línea de la llamada a la función de interés. De hecho se podría llegar a evitar usando una inyección de dependencias, por ejemplo si la llamada la paremetrizamos en una configuración inicial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El resultado que veríamos en pantalla es (notad cómo también se incluyen los valores pasados como parámetros a la función, 30 y 10 en este caso):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;PerformanceEntry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;entryType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;67.022801&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;999.952593&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  NodeJS profiler
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;NodeJS&lt;/code&gt; inluye un &lt;code&gt;profiler&lt;/code&gt; nativo. Para emplearlo es necesario ejecutar la aplicación en modo &lt;code&gt;profiler&lt;/code&gt;. En este paso la aplicación se ejecutará normalmente y además creará un fichero con información sobre la ejecución. Dicho fichero no es interpretable directamente, por lo que es necesario transformarlo. El siguiente fragmento de código muestra el proceso completo:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

node --prof perf_profile.js
node --prof-process isolate-0x27c5960-v8.log &amp;gt; processed.txt


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;El fichero generado tiene una apariencia similar a este:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="o"&gt;[&lt;/span&gt;JavaScript]:
   ticks  total  nonlib   name
    395   38.7%   47.6%  Builtin: GetProperty
     44    4.3%    5.3%  Builtin: Subtract
     28    2.7%    3.4%  Builtin: OrdinaryToPrimitive_Number
     23    2.3%    2.8%  LazyCompile: &lt;span class="k"&gt;*&lt;/span&gt;div /home/andres/blog/perf_profile.js:5:13
     15    1.5%    1.8%  Builtin: NonNumberToNumeric
     10    1.0%    1.2%  Builtin: NonPrimitiveToPrimitive_Number
      9    0.9%    1.1%  Builtin: CallFunction_ReceiverIsNotNullOrUndefined
      8    0.8%    1.0%  Builtin: CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit
      6    0.6%    0.7%  Builtin: DatePrototypeValueOf
      4    0.4%    0.5%  Builtin: DatePrototypeToPrimitive
      4    0.4%    0.5%  Builtin: Call_ReceiverIsNotNullOrUndefined
      1    0.1%    0.1%  Builtin: StoreIC
      1    0.1%    0.1%  Builtin: LoadIC_Uninitialized



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Y este es el resultado de otra aplicación, un poco más larga que la de ejemplo, donde se pueden ver las llamadas a métodos de la librería &lt;a href="https://turfjs.org/" rel="noopener noreferrer"&gt;turfjs&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 [JavaScript]:
   ticks  total  nonlib   name
  10109   13.8%   13.8%  LazyCompile: *bearing /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:7273:17
   9264   12.6%   12.7%  LazyCompile: *distance /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:4742:18
   7148    9.7%    9.8%  LazyCompile: *&amp;lt;anonymous&amp;gt; /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:9883:32
   3196    4.4%    4.4%  LazyCompile: *degreesToRadians /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:598:26
   2517    3.4%    3.4%  LazyCompile: *searchFirstBoundingBox /home/andres/dev/outtrack/gis.js:41:26
   2023    2.8%    2.8%  LazyCompile: *bearingToAzimuth /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:569:26
   1743    2.4%    2.4%  Builtin: CompileLazy
   1651    2.2%    2.3%  LazyCompile: *coordEach /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:832:19
   1641    2.2%    2.2%  LazyCompile: *getCoord /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:1755:18
   1616    2.2%    2.2%  LazyCompile: *&amp;lt;anonymous&amp;gt; /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:1518:42
   1227    1.7%    1.7%  LazyCompile: *&amp;lt;anonymous&amp;gt; /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:1379:32
   1006    1.4%    1.4%  LazyCompile: *getCoords /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:1780:19
    989    1.3%    1.4%  LazyCompile: *geomEach /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:1222:18
    865    1.2%    1.2%  LazyCompile: *searchBoundingBox /home/andres/dev/outtrack/gis.js:51:21
    844    1.2%    1.2%  LazyCompile: *feature /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:93:17
    767    1.0%    1.0%  LazyCompile: *&amp;lt;anonymous&amp;gt; /home/andres/dev/outtrack/node_modules/@turf/turf/turf.js:1508:35



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Como se puede ver, la interpretación de este fichero no es trivial. Por ello han surgido herramientas que muestran la misma información de manera más visual. &lt;a href="https://clinicjs.org/" rel="noopener noreferrer"&gt;clinicjs&lt;/a&gt; es un buen ejemplo. Se trata de una &lt;code&gt;suite&lt;/code&gt; de análisis de rendimiento que incluye varias herramientas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;clinic doctor&lt;/code&gt;, para el análisis de uso de CPU, memoria o retardo del &lt;code&gt;event loop&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clinick flame&lt;/code&gt;, que muestra un &lt;code&gt;flamegraph&lt;/code&gt;, esto, una representación de las llamadas a funciones, donde en el eje Y se muestra el anidamiento de las mismas, y en el eje X el tiempo que se estuvieron ejecutando. Este tipo de gráfica es lo más paracido, en versión visual, a la &lt;code&gt;Performance API&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Faecostas%2Fblog%2Fmaster%2Fperformance%2Fimages%2Fflamechart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Faecostas%2Fblog%2Fmaster%2Fperformance%2Fimages%2Fflamechart.png" alt="flamechart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Faecostas%2Fblog%2Fmaster%2Fperformance%2Fimages%2Fdoctor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Faecostas%2Fblog%2Fmaster%2Fperformance%2Fimages%2Fdoctor.png" alt="doctor"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>performance</category>
      <category>profiling</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Complejidad algorítmica o cómo mejorar el tiempo de ejecución</title>
      <dc:creator>Andrés Estévez</dc:creator>
      <pubDate>Sat, 21 Dec 2019 20:18:17 +0000</pubDate>
      <link>https://dev.to/andres_aec/complejidad-algoritmica-o-como-mejorar-el-tiempo-de-ejecucion-3hfc</link>
      <guid>https://dev.to/andres_aec/complejidad-algoritmica-o-como-mejorar-el-tiempo-de-ejecucion-3hfc</guid>
      <description>&lt;p&gt;¿Deberíamos reimplementar nuestra aplicación, o parte de ella, en un lenguaje más rápido? ¿Tendríamos que dar más recursos a nuestras máquinas? ¿Habría, incluso, que plantear un cambio de arquitectura y optar por una que facilite el paralelismo? Todas ellas son preguntas que nos hemos planteado alguna vez, especialmente cuando nuestra aplicación incrementa el uso de recursos y el rendimiento del sistema se degrada. En este tipo de situaciones, antes de inclinarse por una opción u otra, conviene averiguar cuál es la raíz del problema proponer una solución que actúe sobre dicha raíz.&lt;/p&gt;

&lt;p&gt;En este post se explora una de las causas que ralentizan nuestras aplicaciones: la complejidad algorítmica. ¿Cómo varía el tiempo de ejecución al variar el número de datos a procesar? ¿Y los recursos del sistema, como la RAM o CPU? Veremos que, en función de cómo aumente el tiempo de ejecución al incrementar el tamaño de los datos de entrada, tendremos que nuestro algoritmo se comporta de manera:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constante: los recursos que emplea el algoritmo no dependen del tamaño de los datos&lt;/li&gt;
&lt;li&gt;Lineal: los recursos necesarios aumentan de manera lineal al tamaño de los datos (ej.: el doble de datos, el doble de tiempo)&lt;/li&gt;
&lt;li&gt;Logarítmico: el incremento de tiempo sigue una respuesta logarítmica&lt;/li&gt;
&lt;li&gt;Cuadrático: los recursos incrementan de manera cuadrática con el número de elementos en el conjunto de datos de la entrada&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sin pérdida de generalidad veamos un ejemplo concreto: dado un array de números, se pide obtener los índices de par de números que suman un determinado valor. Si bien se trata de un ejemplo ilustrativo, es trasladable a una aplicación real. Los casos donde tenemos que recorrer un array y relacionarlo con alguno o algunos de los demás elementos son muy comunes, por ejemplo, en procesado de imágenes, procesado de datos de información geográfica, algoritmos de compresión, etc.&lt;/p&gt;

&lt;p&gt;Partamos del siguiente array:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;si el valor buscado es el &lt;code&gt;7&lt;/code&gt; la solución será &lt;code&gt;(1, 3)&lt;/code&gt;, ya que el &lt;code&gt;2&lt;/code&gt; y el &lt;code&gt;5&lt;/code&gt; son los únicos elementos que suman &lt;code&gt;7&lt;/code&gt;. ¿Cuál sería la lógica del algoritmo para resolver este problema? Veamos varias alternativas y analicemos cuál es su rendimiento.&lt;/p&gt;

&lt;p&gt;A menudo la primera opción que se nos ocurre para este tipo de problemas es la llamada comúnmemente &lt;code&gt;fuerza bruta&lt;/code&gt; y consiste en analizar todas las combinaciones posibles. Para cada elemento del array, que llamaremos elemento de referencia, buscaremos si hay algún número que sume &lt;code&gt;7&lt;/code&gt; con el número de referencia. Para el caso que nos ocupa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;empezamos con el &lt;code&gt;1&lt;/code&gt; como referencia y recorremos el resto de elementos buscando un &lt;code&gt;6&lt;/code&gt;, esto es, el complementario para que la suma de ambos sea &lt;code&gt;7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;en la segunda iteración la referencia es &lt;code&gt;2&lt;/code&gt;, por lo que buscamos un &lt;code&gt;5&lt;/code&gt;, que encontraremos en la última posición del array.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function searchPairSimple(data, target) {
    for (i = 0; i &amp;lt; data.length; i++) {
        for (j = 0; j &amp;lt; data.length; j++) {
            if (i == j) continue;

            if (data[i] + data[j] === target) {
                return [i, j];
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Los tiempos de ejecución para esta solución en función del número de elementos del array son:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tamaño&lt;/th&gt;
&lt;th&gt;Algoritmo&lt;br&gt; básico&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;0.64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;0.75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;2.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;12.03&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000&lt;/td&gt;
&lt;td&gt;47.7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;¿Cómo podemos mejorar el rendimiento de esta solución? Fijémonos en el segundo bucle. Empieza en el cero, lo que significa que se van a probar combinaciones que ya se habían probado. Por ejemplo, cuando la &lt;code&gt;i&lt;/code&gt; valía &lt;code&gt;0&lt;/code&gt; y la &lt;code&gt;j&lt;/code&gt; &lt;code&gt;1&lt;/code&gt;, los valores que teníamos eran el 1 y 2, que suman 3, y por tanto no cumplen la condición buscada. Ahora bien, cuando la &lt;code&gt;i&lt;/code&gt; vale &lt;code&gt;1&lt;/code&gt; y la &lt;code&gt;j&lt;/code&gt; vale &lt;code&gt;0&lt;/code&gt;, los valores vuelven a ser el 1 y el 2. Volver a probar pares que ya habían sido descartados es una pérdida de tiempo y recursos, ¿es posible evitarlo? Basta inicializar la &lt;code&gt;j&lt;/code&gt; del segundo bucle al valor siguiente de la &lt;code&gt;i&lt;/code&gt;. De esta manera las iteracciones se reducen a la mitad.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    function searchPairSimpleOptimized(data, target) {
        for (i = 0; i &amp;lt; data.length - 1; i++) {
            for (j = i+1; j &amp;lt; data.length; j++) {

                if (data[i] + data[j] === target) {
                    return [i, j];
                }    
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tamaño&lt;/th&gt;
&lt;th&gt;Algoritmo&lt;br&gt; básico&lt;/th&gt;
&lt;th&gt;Algoritmo &lt;br&gt; microoptimizado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;0.64&lt;/td&gt;
&lt;td&gt;0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;0.75&lt;/td&gt;
&lt;td&gt;0.38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;2.98&lt;/td&gt;
&lt;td&gt;1.47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;12.03&lt;/td&gt;
&lt;td&gt;5.83&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000&lt;/td&gt;
&lt;td&gt;47.7&lt;/td&gt;
&lt;td&gt;23.27&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;¿Es posible mejorarlo aún más? Fijémonos en el último valor del array, el 5. Se ha leído tantas veces como longitud tiene el array, es decir, en cada pasada por el array lo estamos leyendo otra vez. Con el resto de número pasa algo similar: cuanto más a la derecha se encuentren, más veces se habrán leído. ¿Habría forma de leerlos una sola vez? Es decir, cuando estemos en cualquier posición del array, ¿podríamos saber si existe el número complementario sin necesidad de volver a recorrerlo? Dicho de otra forma, ¿podríamos &lt;code&gt;memorizar&lt;/code&gt; el contenido del array para no tener que recorrerlo más? La respuesta es sí. Veamos el siguiente código:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function searchPairDictionary(data, target) {

    let dict = {}
    for (let i = 0; i &amp;lt; data.length; i++) {
        dict[data[i]] = i; 

        if (dict[ target - data[i] ] !== undefined &amp;amp;&amp;amp; 
            dict[ target - data[i] ]  !== i) {

                return [i, dict[ target - data[i]]];
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;La idea es la siguiente: al mismo tiempo que recorremos el array vamos almacenando los valores leídos en un diccionario, cuya clave es el valor que hay en la posición actual del array, y el valor es el índice en el que se encuentra. ¿Por qué esta estructura? La clave es lo que usamos para buscar, mientras que el valor es lo que buscamos: la posición del elemento en el array. Así, cuando hayamos leído el valor &lt;code&gt;1&lt;/code&gt; del array podremos 'preguntarle' al diccionario si tiene un &lt;code&gt;6&lt;/code&gt;. De esta forma ahorramos volver a iterar sobre todo el array.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tamaño&lt;/th&gt;
&lt;th&gt;Algoritmo&lt;br&gt; básico&lt;/th&gt;
&lt;th&gt;Algoritmo &lt;br&gt; microoptimizado&lt;/th&gt;
&lt;th&gt;Diccionario&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;0.64&lt;/td&gt;
&lt;td&gt;0.48&lt;/td&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;0.75&lt;/td&gt;
&lt;td&gt;0.38&lt;/td&gt;
&lt;td&gt;0.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;2.98&lt;/td&gt;
&lt;td&gt;1.47&lt;/td&gt;
&lt;td&gt;0.23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2000&lt;/td&gt;
&lt;td&gt;12.03&lt;/td&gt;
&lt;td&gt;5.83&lt;/td&gt;
&lt;td&gt;0.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000&lt;/td&gt;
&lt;td&gt;47.7&lt;/td&gt;
&lt;td&gt;23.27&lt;/td&gt;
&lt;td&gt;0.59&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;El tiempo de ejecución ha mejorado, especialmente cuando el tamaño del array crece. Además, comparándolo con los tiempos de las dos versiones anteriores del algoritmo la mejora es todavía mayor. Se trata pues, de un buen ejemplo, de cómo cambiando la lógica de nuestra aplicación es posible mejorar mucho el rendimiento sin necesidad de ampliar los recursos disponibles o de emplear arquitecturas software complejas. Si bien, esta mejora no ha sido a coste cero ya que, a diferencia de las otras soluciones, estamos empleando más memoria, la necesaria para el diccionario.&lt;/p&gt;

&lt;p&gt;La siguiente imagen representa gráficamente la evolución de los tiempos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EE24i-sP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9o8wb0f6d3nkn2etw30o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EE24i-sP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9o8wb0f6d3nkn2etw30o.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es buena práctica tener siempre en mente cuál es la complejidad algorítmica de nuestro código. La notación &lt;code&gt;big O&lt;/code&gt;, que indica cuál es el orden de mágnitud máximo de nuestro algoritmo, es una de las más extendidas. Así, un algoritmo &lt;code&gt;O(n^2)&lt;/code&gt; tardará, como mucho, el cuadrado del tiempo de ejecución de un elemento, pero podría ser menos. La siguiente gráfica muestra cómo evolucionan los tiempos de varios &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YOuTWoFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ai4kxwiz01bazm5enz53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YOuTWoFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ai4kxwiz01bazm5enz53.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://www.geeksforgeeks.org/analysis-algorithms-big-o-analysis/"&gt;https://www.geeksforgeeks.org/analysis-algorithms-big-o-analysis/&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
