Cómo escribir JavaScript rápido y con memoria eficiente

 

 

 

  • Smart Interface Design Patterns, 10h video + UX training
  • Behavioral Design Workshop, with Susan and Guthrie Weinschenk

  • Índice
    1. Entonces, ¿cómo funciona JavaScript en V8?
    2. Recolección de basura
      1. Eliminación de conceptos erróneos
      2. Reglas de juego
      3. Funciones
      4. Cierres
      5. Temporizadores
    3. Sea consciente de las trampas de rendimiento
    4. Consejos de optimización V8
      1. Objetos vs. Matrices: ¿cuál debo utilizar?
      2. Consejos al utilizar objetos
      3. Consejos al utilizar matrices
    5. Optimización de su aplicación
      1. Evaluación comparativa
      2. Perfilado

    Existen muchos errores comunes cuando se trata de escribir código rápido y con uso eficiente de la memoria. En este artículo exploraremos algunos enfoques probados para escribir código que funcione mejor.

     

    Los motores JavaScript como el V8 de Google (Chrome, Node) están diseñados específicamente para la ejecución rápida de grandes aplicaciones JavaScript. A medida que desarrolla, si le importa el uso y el rendimiento de la memoria, debe tener en cuenta algo de lo que sucede detrás de escena en el motor JavaScript del navegador de su usuario.

    Ya sea V8, SpiderMonkey (Firefox), Carakan (Opera), Chakra (IE) u otra cosa, hacerlo puede ayudarle a optimizar mejor sus aplicaciones . Eso no quiere decir que uno deba optimizar para un solo navegador o motor. Nunca hagas eso.

    Sin embargo, debes hacerte preguntas como:

    • ¿Hay algo que pueda hacer de manera más eficiente en mi código?
    • ¿Qué optimizaciones (comunes) hacen los motores JavaScript populares?
    • ¿Para qué no puede optimizar el motor? ¿Puede el recolector de basura limpiar lo que espero?

    Hay muchos errores comunes cuando se trata de escribir código rápido y con uso eficiente de la memoria, y en este artículo exploraremos algunos enfoques probados para escribir código que funcione mejor.

     

    Entonces, ¿cómo funciona JavaScript en V8?

    Si bien es posible desarrollar aplicaciones a gran escala sin un conocimiento profundo de los motores JavaScript, cualquier propietario de un automóvil le dirá que ha mirado debajo del capó al menos una vez. Como Chrome es mi navegador preferido, voy a hablar un poco sobre su motor JavaScript. V8 se compone de algunas piezas centrales.

    • Un compilador base , que analiza su JavaScript y genera código de máquina nativo antes de ejecutarlo, en lugar de ejecutar código de bytes o simplemente interpretarlo. Inicialmente, este código no está muy optimizado.
    • V8 representa sus objetos en un modelo de objetos . Los objetos se representan como matrices asociativas en JavaScript, pero en V8 se representan con clases ocultas , que son un sistema de tipos interno para búsquedas optimizadas.
    • El perfilador de tiempo de ejecución monitorea el sistema que se está ejecutando e identifica funciones "calientes" (es decir, código que termina funcionando durante mucho tiempo).
    • Un compilador de optimización recompila y optimiza el código "activo" identificado por el perfilador de tiempo de ejecución y realiza optimizaciones como la inserción (es decir, reemplazar un sitio de llamada de función con el cuerpo del destinatario).
    • V8 admite la desoptimización , lo que significa que el compilador de optimización puede rescatar el código generado si descubre que algunas de las suposiciones que hizo sobre el código optimizado eran demasiado optimistas.
    • Dispone de recolector de basura . Comprender cómo funciona puede ser tan importante como JavaScript optimizado.

    Recolección de basura

    La recolección de basura es una forma de gestión de la memoria . Es donde tenemos la noción de un recolector que intenta recuperar la memoria ocupada por objetos que ya no se utilizan. En un lenguaje de recolección de basura como JavaScript, los objetos a los que su aplicación todavía hace referencia no se limpian.

    En la mayoría de los casos, no es necesario eliminar la referencia a objetos manualmente. Simplemente colocando las variables donde deben estar (idealmente, lo más locales posible, es decir, dentro de la función donde se usan versus un alcance externo), las cosas deberían funcionar.

     

    No es posible forzar la recolección de basura en JavaScript. No querrás hacer esto, porque el proceso de recolección de basura está controlado por el tiempo de ejecución y, por lo general, sabe mejor cuándo se deben limpiar las cosas.

    Eliminación de conceptos erróneos

    En bastantes discusiones en línea sobre la recuperación de memoria en JavaScript, deletese menciona la palabra clave, ya que aunque se suponía que se usaría solo para eliminar claves de un mapa, algunos desarrolladores piensan que se puede forzar la desreferenciación usándola. Evite usarlo deletesi puede. En el siguiente ejemplo, delete o.xhace mucho más daño que bien detrás de escena, ya que cambia ola clase oculta y lo convierte en un objeto lento genérico.

    var o = { x: 1 };delete o.x; // trueo.x; // undefined

    Dicho esto, es casi seguro que encontrará referencias a deletemuchas bibliotecas populares de JavaScript; tiene un propósito en el lenguaje. La conclusión principal aquí es evitar modificar la estructura de los objetos calientes en tiempo de ejecución. Los motores de JavaScript pueden detectar estos objetos "calientes" e intentar optimizarlos. Esto es más fácil si la estructura del objeto no cambia mucho durante su vida y deletepuede desencadenar dichos cambios.

    También existen ideas erróneas sobre cómo nullfunciona. Establecer una referencia de objeto a nullno "anula" el objeto. Establece la referencia del objeto en null. Usar o.x = nulles mejor que usar delete, pero probablemente ni siquiera sea necesario.

    var o = { x: 1 };o = null;o; // nullo.x // TypeError

    Si esta referencia fue la última referencia al objeto, el objeto es elegible para la recolección de basura. Si la referencia no fue la última referencia al objeto, se puede acceder al objeto y no se recolectará como basura.

    Otra nota importante a tener en cuenta es que el recolector de basura no limpia las variables globales durante la vida útil de su página. Independientemente de cuánto tiempo esté abierta la página, las variables cuyo ámbito es el objeto global de tiempo de ejecución de JavaScript permanecerán.

    var myGlobalNamespace = {};

    Los valores globales se limpian cuando actualiza la página, navega a una página diferente, cierra pestañas o sale de su navegador. Las variables con ámbito de función se limpian cuando una variable queda fuera de alcance. Cuando las funciones han salido y no hay más referencias a ellas, la variable se limpia.

    Reglas de juego

    Para darle al recolector de basura la oportunidad de recolectar tantos objetos como sea posible lo antes posible, no guardes objetos que ya no necesites . Esto ocurre principalmente de forma automática; aquí hay algunas cosas a tener en cuenta.

    • Como se mencionó anteriormente, una mejor alternativa a la desreferenciación manual es utilizar variables con un alcance apropiado. Es decir, en lugar de una variable global que se anula, simplemente use una variable local de función que salga del alcance cuando ya no sea necesaria. Esto significa un código más limpio con menos de qué preocuparse.
    • Asegúrese de desvincular los detectores de eventos donde ya no sean necesarios, especialmente cuando los objetos DOM a los que están vinculados están a punto de ser eliminados.
    • Si está utilizando un caché de datos localmente, asegúrese de limpiarlo o usar un mecanismo de antigüedad para evitar que se almacenen grandes cantidades de datos que es poco probable que reutilice.

    Funciones

    A continuación, veamos las funciones. Como ya hemos dicho, la recolección de basura funciona recuperando bloques de memoria (objetos) a los que ya no se puede acceder. Para ilustrar mejor esto, aquí hay algunos ejemplos.

     

    function foo() { var bar = new LargeObject(); bar.someCall();}

    Cuando fooregresa, el objeto al que barapunta está automáticamente disponible para la recolección de basura, porque no queda nada que tenga una referencia a él.

    Compara esto con:

    function foo() { var bar = new LargeObject(); bar.someCall(); return bar;}// somewhere elsevar b = foo();

    Ahora tenemos una referencia al objeto que sobrevive a la llamada y persiste hasta que la persona que llama asigna algo más b(o bsale del alcance).

    Cierres

    Cuando ve una función que devuelve una función interna, esa función interna tendrá acceso al alcance externo incluso después de que se ejecute la función externa. Esto es básicamente un cierre , una expresión que puede funcionar con variables establecidas dentro de un contexto específico. Por ejemplo:

    function sum (x) { function sumIt(y) { return x + y; }; return sumIt;}// Usagevar sumA = sum(4);var sumB = sumA(3);console.log(sumB); // Returns 7

    El objeto de función creado dentro del contexto de ejecución de la llamada a sumno se puede recolectar como basura, ya que está referenciado por una variable global y aún es muy accesible. Todavía se puede ejecutar mediante sumA(n).

    Veamos otro ejemplo. ¿Aquí podemos acceder largeStr?

    var a = function () { var largeStr = new Array(1000000).join('x'); return function () { return largeStr; };}();

    Sí, podemos hacerlo a través de a(), por lo que no se recopila. ¿Que tal este?

    var a = function () { var smallStr = 'x'; var largeStr = new Array(1000000).join('x'); return function (n) { return smallStr; };}();

    Ya no podemos acceder a él y es candidato para la recolección de basura.

    Temporizadores

    Uno de los peores lugares para filtrar es en un bucle o en setTimeout()/ setInterval(), pero esto es bastante común.

    Considere el siguiente ejemplo.

    var myObj = { callMeMaybe: function () { var myRef = this; var val = setTimeout(function () { console.log('Time is running out!'); myRef.callMeMaybe(); }, 1000); }};

    Si luego ejecutamos:

    myObj.callMeMaybe();

    Para iniciar el cronómetro, podemos ver cada segundo “¡El tiempo se acaba!” Si luego ejecutamos:

    myObj = null;

    El cronómetro seguirá funcionando. myObjno se recolectará basura ya que el cierre pasado setTimeoutdebe mantenerse activo para poder ejecutarse. A su vez, contiene referencias a myObjlo que captura myRef. Esto sería lo mismo si hubiéramos pasado el cierre a cualquier otra función, manteniendo las referencias a ella.

     

    También vale la pena tener en cuenta que las referencias dentro de una llamada setTimeout/ setInterval, como las funciones, deberán ejecutarse y completarse antes de que puedan ser recolectadas como basura.

    Sea consciente de las trampas de rendimiento

    Es importante no optimizar nunca el código hasta que realmente sea necesario. Esto no se puede enfatizar lo suficiente. Es fácil ver una serie de microevaluaciones que muestran que N es más óptimo que M en V8, pero pruébelo en un módulo de código real o en una aplicación real, y el verdadero impacto de esas optimizaciones puede ser mucho más mínimo de lo que cree. esperaban.

    Digamos que queremos crear un módulo que:

    • Toma una fuente local de datos que contiene elementos con una identificación numérica,
    • Dibuja una tabla que contiene estos datos,
    • Agrega controladores de eventos para alternar una clase cuando un usuario hace clic en cualquier celda.

    Hay algunos factores diferentes en este problema, aunque es bastante sencillo de resolver. ¿Cómo almacenamos los datos? ¿Cómo dibujamos la tabla de manera eficiente y la agregamos al DOM? ¿Cómo manejamos los eventos en esta mesa de manera óptima?

    Una primera (ingenua) solución a este problema podría ser almacenar cada dato disponible en un objeto que agrupamos en una matriz. Se podría usar jQuery para iterar a través de los datos y dibujar la tabla, luego agregarla al DOM. Finalmente, se podría usar el enlace de eventos para agregar el comportamiento de clic que deseamos.

    Nota: Esto NO es lo que deberías hacer

    var moduleA = function () { return { data: dataArrayObject, init: function () { this.addTable(); this.addEvents(); }, addTable: function () { for (var i = 0; i rows; i++) { $tr = $('tr/tr'); for (var j = 0; j this.data.length; j++) { $tr.append('td' + this.data[j]['id'] + '/td'); } $tr.appendTo($tbody); } }, addEvents: function () { $('table td').on('click', function () { $(this).toggleClass('active'); }); } };}();

    Simple, pero hace el trabajo.

    Sin embargo, en este caso, los únicos datos que estamos iterando son los ID, una propiedad numérica que podría representarse de manera más simple en una matriz estándar. Curiosamente, el uso directo DocumentFragmentde métodos DOM nativos es más óptimo que usar jQuery (de esta manera) para nuestra generación de tablas y, por supuesto, la delegación de eventos suele ser más eficaz que vincular cada uno de ellos tdindividualmente.

    Tenga en cuenta que jQuery se usa DocumentFragmentinternamente detrás de escena, pero en nuestro ejemplo, el código llama append()dentro de un bucle y cada una de estas llamadas tiene poco conocimiento de la otra, por lo que es posible que no pueda optimizarse para este ejemplo. Con suerte, esto no debería ser un problema, pero asegúrese de comparar su propio código para estar seguro. Korean Beauty

     

    En nuestro caso, agregar estos cambios da como resultado algunas buenas ganancias de rendimiento (esperadas). La delegación de eventos proporciona una mejora decente con respecto a la simple vinculación, y optar por elladocumentFragment fue un verdadero impulso.

    var moduleD = function () { return { data: dataArray, init: function () { this.addTable(); this.addEvents(); }, addTable: function () { var td, tr; var frag = document.createDocumentFragment(); var frag2 = document.createDocumentFragment(); for (var i = 0; i rows; i++) { tr = document.createElement('tr'); for (var j = 0; j this.data.length; j++) { td = document.createElement('td'); td.appendChild(document.createTextNode(this.data[j])); frag2.appendChild(td); } tr.appendChild(frag2); frag.appendChild(tr); } tbody.appendChild(frag); }, addEvents: function () { $('table').on('click', 'td', function () { $(this).toggleClass('active'); }); } };}();

    Entonces podríamos buscar otras formas de mejorar el rendimiento. Es posible que haya leído en alguna parte que usar el patrón prototípico es más óptimo que el patrón del módulo (confirmamos que no lo era antes), o que haya escuchado que el uso de marcos de plantillas de JavaScript está altamente optimizado. A veces lo son, pero utilícelos porque crean código legible. Además, ¡precompila!. Probemos y descubramos qué tan cierto es esto en la práctica.

    moduleG = function () {};moduleG.prototype.data = dataArray;moduleG.prototype.init = function () { this.addTable(); this.addEvents();};moduleG.prototype.addTable = function () { var template = _.template($('#template').text()); var html = template({'data' : this.data}); $tbody.append(html);};moduleG.prototype.addEvents = function () { $('table').on('click', 'td', function () { $(this).toggleClass('active'); });};var modG = new moduleG();

    Resulta que en este caso los beneficios de rendimiento son insignificantes. Optar por plantillas y prototipos realmente no ofrecía nada más que lo que teníamos antes. Dicho esto, el rendimiento no es realmente la razón por la que los desarrolladores modernos utilizan cualquiera de estas cosas: es la legibilidad, el modelo de herencia y la capacidad de mantenimiento que aportan a su código base.

    Los problemas más complejos incluyen dibujar imágenes de manera eficiente usando lienzo y manipular datos de píxeles con o sin matrices escritas.

    Siempre revise detenidamente los micropuntos de referencia antes de explorar su uso en su aplicación. Algunos de ustedes recordarán el desempate de plantillas de JavaScript y el desempate extendido que siguió . Desea asegurarse de que las pruebas no se vean afectadas por restricciones que probablemente no verá en aplicaciones del mundo real: pruebe las optimizaciones juntas en el código real.

    Consejos de optimización V8

    Si bien detallar cada optimización de V8 está fuera del alcance de este artículo, ciertamente hay muchos consejos que vale la pena mencionar. Tenga esto en cuenta y reducirá las posibilidades de escribir código de bajo rendimiento.

     

    • Ciertos patrones harán que V8 abandone las optimizaciones. Un try-catch, por ejemplo, provocará dicho rescate. Para obtener más información sobre qué funciones se pueden optimizar y qué no, puede utilizar --trace-opt file.jsla utilidad de shell d8 que viene con V8.
    • Si le importa la velocidad, intente con todas sus fuerzas mantener sus funciones monomórficas, es decir, asegúrese de que las variables (incluidas propiedades, matrices y parámetros de funciones) solo contengan objetos con la misma clase oculta. Por ejemplo, no hagas esto:
    function add(x, y) { return x+y;}add(1, 2);add('a','b');add(my_custom_object, undefined);
    • No cargue desde elementos no inicializados o eliminados. Esto no hará una diferencia en la producción, pero hará que las cosas sean más lentas.
    • No escriba funciones enormes, ya que son más difíciles de optimizar.

    Para obtener más consejos, vea la charla de Google I/O de Daniel Clifford Rompiendo el límite de velocidad de JavaScript con V8 , ya que cubre bien estos temas. También vale la pena leer Optimización para V8: Serie A.

    Objetos vs. Matrices: ¿cuál debo utilizar?

    • Si desea almacenar un montón de números o una lista de objetos del mismo tipo, utilice una matriz.
    • Si lo que necesita semánticamente es un objeto con un montón de propiedades (de distintos tipos), utilice un objeto con propiedades. Esto es bastante eficiente en términos de memoria y también bastante rápido.
    • Los elementos indexados con números enteros, independientemente de si están almacenados en una matriz o en un objeto, son mucho más rápidos de iterar que las propiedades del objeto .
    • Las propiedades de los objetos son bastante complejas: se pueden crear con definidores y con diferente enumerabilidad y capacidad de escritura. Los elementos de las matrices no se pueden personalizar tanto: existen o no. A nivel de motor, esto permite una mayor optimización en términos de organización de la memoria que representa la estructura. Esto es particularmente beneficioso cuando la matriz contiene números. Por ejemplo, cuando necesite vectores, no defina una clase con propiedades x, y, z; use una matriz en su lugar.

    En realidad, sólo hay una diferencia importante entre objetos y matrices en JavaScript, y esa es la lengthpropiedad mágica de las matrices. Si usted mismo realiza un seguimiento de esta propiedad, los objetos en V8 deberían ser tan rápidos como las matrices.

    Consejos al utilizar objetos

    • Crea objetos usando una función constructora. Esto garantiza que todos los objetos creados con él tengan la misma clase oculta y ayuda a evitar cambiar estas clases.
    • No hay restricciones en la cantidad de tipos de objetos diferentes que puede usar en su aplicación o en su complejidad (dentro de lo razonable: las cadenas de prototipos largas tienden a doler, y los objetos con solo un puñado de propiedades obtienen una representación especial que es un poco más rápida que los más grandes). objetos). Para objetos "calientes", intente mantener las cadenas de prototipos cortas y el recuento de campos bajo.

    Clonación de objetos La clonación de objetos es un problema común para los desarrolladores de aplicaciones. Si bien es posible comparar qué tan bien funcionan varias implementaciones con este tipo de problema en V8, tenga mucho cuidado al copiar cualquier cosa. Copiar cosas importantes suele ser lento; no lo hagas. for..inLos bucles en JavaScript son particularmente malos para esto, ya que tienen una especificación diabólica y probablemente nunca serán rápidos en ningún motor para objetos arbitrarios.

     

    Cuando sea absolutamente necesario copiar objetos en una ruta de código de rendimiento crítico (y no pueda salir de esta situación), use una matriz o una función personalizada de "constructor de copia" que copie cada propiedad explícitamente. Esta es probablemente la forma más rápida de hacerlo:

    function clone(original) { this.foo = original.foo; this.bar = original.bar;}var copy = new clone(original);

    Funciones almacenadas en caché en el patrón del módulo Guardar en caché sus funciones cuando utiliza el patrón del módulo puede generar mejoras en el rendimiento. Vea a continuación un ejemplo en el que la variación que probablemente esté acostumbrado a ver es más lenta, ya que obliga a crear nuevas copias de las funciones miembro todo el tiempo.

    Aquí hay una prueba de rendimiento del prototipo versus el patrón del módulo.

    // Prototypal pattern Klass1 = function () {} Klass1.prototype.foo = function () { log('foo'); } Klass1.prototype.bar = function () { log('bar'); } // Module pattern Klass2 = function () { var foo = function () { log('foo'); }, bar = function () { log('bar'); }; return { foo: foo, bar: bar } } // Module pattern with cached functions var FooFunction = function () { log('foo'); }; var BarFunction = function () { log('bar'); }; Klass3 = function () { return { foo: FooFunction, bar: BarFunction } } // Iteration tests // Prototypal var i = 1000, objs = []; while (i--) { var o = new Klass1() objs.push(new Klass1()); o.bar; o.foo; } // Module pattern var i = 1000, objs = []; while (i--) { var o = Klass2() objs.push(Klass2()); o.bar; o.foo; } // Module pattern with cached functions var i = 1000, objs = []; while (i--) { var o = Klass3() objs.push(Klass3()); o.bar; o.foo; }// See the test for full details

    Nota: Si no necesita una clase, evite la molestia de crear una. A continuación se muestra un ejemplo de cómo obtener mejoras en el rendimiento eliminando por completo la sobrecarga de clase .

    Consejos al utilizar matrices

    A continuación, veamos algunos consejos para matrices. En general, no elimine elementos de la matriz . Haría que la matriz pase a una representación interna más lenta. Cuando el conjunto de claves se vuelve escaso, V8 eventualmente cambiará los elementos al modo de diccionario, que es aún más lento.

    Literales de matriz Los literales de matriz son útiles porque dan una pista a la VM sobre el tamaño y tipo de la matriz. Por lo general, son buenos para arreglos de tamaño pequeño a mediano.

     

    // Here V8 can see that you want a 4-element array containing numbers:var a = [1, 2, 3, 4];// Don't do this:a = []; // Here V8 knows nothing about the arrayfor(var i = 1; i = 4; i++) { a.push(i);}

    Almacenamiento de tipos individuales vs. Tipos mixtos Nunca es una buena idea mezclar valores de diferentes tipos (por ejemplo, números, cadenas, indefinidos o verdadero/falso) en la misma matriz (es decir, var arr = [1, “1”, undefined, true, “true”])

    Prueba de rendimiento de inferencia de tipos

    Como podemos ver en los resultados, la matriz de intses la más rápida.

    Arreglos dispersos versus arreglos completos Cuando utilice arreglos dispersos, tenga en cuenta que el acceso a los elementos que contienen es mucho más lento que en los arreglos completos. Esto se debe a que V8 no asigna un almacén de respaldo plano para los elementos si solo se utilizan algunos de ellos. En cambio, los gestiona en un diccionario, lo que ahorra espacio, pero cuesta tiempo de acceso.

    Prueba de matrices dispersas versus matrices completas .

    La matriz completa sumy sumtodos los elementos de una matriz sin ceros fueron en realidad los más rápidos. Si la matriz completa contiene ceros o no, no debería marcar la diferencia.

    Empacado vs. Matrices con agujeros Evite los "agujeros" en una matriz (creados al eliminar elementos o a[x] = foocon x a.length). Incluso si solo se elimina un elemento de una matriz que de otro modo sería "completa", las cosas serán mucho más lentas.

    "Prueba de matrices empaquetadas frente a perforadas ".

    Matrices de preasignación vs. Creciendo a medida que avanza No asigne previamente arreglos grandes (es decir, elementos de más de 64 KB) a su tamaño máximo; en lugar de eso, crezca a medida que avanza. Antes de pasar a las pruebas de rendimiento de este consejo, tenga en cuenta que esto es específico sólo de algunos motores de JavaScript.

    Nitro (Safari) en realidad trata más favorablemente las matrices preasignadas. Sin embargo, en otros motores (V8, SpiderMonkey), no realizar una preasignación es más eficiente.

    Prueba de matrices preasignadas .

    // Empty arrayvar arr = [];for (var i = 0; i 1000000; i++) { arr[i] = i;}// Pre-allocated arrayvar arr = new Array(1000000);for (var i = 0; i 1000000; i++) { arr[i] = i;}

    Optimización de su aplicación

    En el mundo de las aplicaciones web, la velocidad lo es todo . Ningún usuario quiere que una aplicación de hoja de cálculo tarde unos segundos en resumir una columna completa o que un resumen de sus mensajes tarde un minuto en estar listo. Esta es la razón por la que, a veces, puede resultar fundamental exprimir hasta la última gota de rendimiento adicional posible del código.

    Si bien comprender y mejorar el rendimiento de su aplicación es útil, también puede resultar difícil. Recomendamos los siguientes pasos para solucionar los problemas de rendimiento:

    • Mídalo: encuentre los puntos lentos en su aplicación (~45%)
    • Entiéndalo: descubra cuál es el problema real (~45%)
    • ¡Arreglalo! (~10%)

    Algunas de las herramientas y técnicas recomendadas a continuación pueden ayudar con este proceso.

    Evaluación comparativa

    Hay muchas formas de ejecutar evaluaciones comparativas en fragmentos de JavaScript para probar su rendimiento; la suposición general es que la evaluación comparativa consiste simplemente en comparar dos marcas de tiempo. Uno de esos patrones fue señalado por el equipo jsPerf , y resulta que se utiliza en las suites de referencia de SunSpider y Kraken :

    var totalTime, start = new Date, iterations = 1000;while (iterations--) { // Code snippet goes here}// totalTime → the number of milliseconds taken// to execute the code snippet 1000 timestotalTime = new Date - start;

    Aquí, el código que se va a probar se coloca dentro de un bucle y se ejecuta un número determinado de veces (por ejemplo, seis). Después de esto, la fecha de inicio se resta de la fecha de finalización para encontrar el tiempo necesario para realizar las operaciones en el bucle.

    Sin embargo, esto simplifica demasiado cómo se deben realizar las evaluaciones comparativas, especialmente si desea ejecutar las evaluaciones comparativas en múltiples navegadores y entornos. La recolección de basura en sí misma puede tener un impacto en sus resultados. Incluso si utiliza una solución como window.performance, aún debe tener en cuenta estos errores.

    Independientemente de si simplemente está ejecutando pruebas comparativas con partes de su código, escribiendo un conjunto de pruebas o codificando una biblioteca de pruebas comparativas, la evaluación comparativa de JavaScript implica mucho más de lo que podría pensar. Para obtener una guía más detallada sobre la evaluación comparativa, recomiendo leer JavaScript Benchmarking de Mathias Bynens y John-David Dalton.

    Perfilado

    Las herramientas para desarrolladores de Chrome tienen un buen soporte para la creación de perfiles de JavaScript . Puede utilizar esta función para detectar qué funciones consumen la mayor parte de su tiempo para luego optimizarlas. Esto es importante, ya que incluso pequeños cambios en su código base pueden tener graves impactos en su rendimie






    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Cómo escribir JavaScript rápido y con memoria eficiente

    Cómo escribir JavaScript rápido y con memoria eficiente

    Smart Interface Design Patterns, 10h video + UX training Behavioral Design Workshop, with Susan and Guthrie Weinschenk Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-como-escribir-javascript-rapido-y-con-memoria-eficiente-807-0.jpg

    2024-05-20

     

    Cómo escribir JavaScript rápido y con memoria eficiente
    Cómo escribir JavaScript rápido y con memoria eficiente

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20