martes, 10 de enero de 2017

Mejorando el rendimiento

Capítulo 9. Mejorando el rendimiento

Este capítulo cubre numerosas mejores prácticas de JavaScript y jQuery,sin un orden en particular. Muchas de estas prácticas están basadas en la presentación jQuery Anti-Patterns for Performance (en inglés) de Paul Irish.

9.1. Guardar la longitud en bucles

En un bucle, no es necesario acceder a la longitud de un array cada vez que se evalúa la condición; dicho valor se puede guardar previamente en una variable.
var myLength = myArray.length;
 
for (var i = 0; i < myLength; i++) {
    // do stuff
}

9.2. Añadir nuevo contenido por fuera de un bucle

Si va a insertar muchos elementos en el DOM, hágalo todo de una sola vez, no de una por vez.
// mal
$.each(myArray, function(i, item) {
   var newListItem = '<li>' + item + '</li>';
   $('#ballers').append(newListItem);
});
 
// mejor: realizar esto
var frag = document.createDocumentFragment();
$.each(myArray, function(i, item) {
    var newListItem = '<li>' + item + '</li>';
    frag.appendChild(newListItem);
});
$('#ballers')[0].appendChild(frag);
 
// o esto:
var myHtml = '';
$.each(myArray, function(i, item) {
    myHtml += '<li>' + item + '</li>';
});
$('#ballers').html(myHtml);

9.3. No repetirse

No se repita; realice las cosas una vez y sólo una, caso contrario lo estará haciendo mal.
// MAL
if ($eventfade.data('currently') != 'showing') {
    $eventfade.stop();
}
 
if ($eventhover.data('currently') != 'showing') {
    $eventhover.stop();
}
 
if ($spans.data('currently') != 'showing') {
    $spans.stop();
}
 
// BIEN
var $elems = [$eventfade, $eventhover, $spans];
$.each($elems, function(i,elem) {
    if (elem.data('currently') != 'showing') {
        elem.stop();
    }
});

9.4. Cuidado con las funciones anónimas

No es aconsejable utilizar de sobremanera las funciones anónimas. Estas son difíciles de depurar, mantener, probar o reutilizar. En su lugar,utilice un objeto literal para organizar y nombrar sus controladores y funciones de devolución de llamada.
// MAL
$(document).ready(function() {
    $('#magic').click(function(e) {
        $('#yayeffects').slideUp(function() {
            // ...
        });
    });
 
    $('#happiness').load(url + ' #unicorns', function() {
        // ...
    });
});
 
// MEJOR
var PI = {
    onReady : function() {
        $('#magic').click(PI.candyMtn);
        $('#happiness').load(PI.url + ' #unicorns', PI.unicornCb);
    },
 
    candyMtn : function(e) {
        $('#yayeffects').slideUp(PI.slideCb);
    },
 
    slideCb : function() { ... },
 
    unicornCb : function() { ... }
};
 
$(document).ready(PI.onReady);

9.5. Optimización de selectores

La optimización de selectores es menos importante de lo que solía ser,debido a la implementación en algunos navegadores de document.querySelectorAll(), pasando la carga de jQuery hacia el navegador. Sin embargo, existen algunos consejos que debe tener en cuenta.

9.5.1. Selectores basados en ID

Siempre es mejor comenzar las selecciones con un ID.
// rápido
$('#container div.robotarm');
 
// super-rápido
$('#container').find('div.robotarm');
El ejemplo que utiliza $.fn.find es más rápido debido a que la primera selección utiliza el motor de selección interno Sizzle — mientras que la selección realizada únicamente por ID utiliza document.getElementById(), el cual es extremadamente rápido debido a que es una función nativa del navegador.

9.5.2. Especificidad

Trate de ser especifico para el lado derecho de la selección y menos especifico para el izquierdo.
// no optimizado
$('div.data .gonzalez');
 
// optimizado
$('.data td.gonzalez');
Use en lo posible etiqueta.clase del lado derecho de la selección, y solo etiqueta o .clase en la parte izquierda.
Evite especificidad excesiva.
$('.data table.attendees td.gonzalez');
 
// mucho mejor: eliminar la parte media de ser posible
$('.data td.gonzalez');
La segunda selección tiene mejor rendimiento debido a que atraviesa menos capas para buscar el elemento.

9.5.3. Evitar el selector universal

Selecciones en donde se especifica de forma implícita o explicita unaselección universal puede resultar muy lento.
$('.buttons > *');         // muy lento
$('.buttons').children();  // mucho mejor
$('.gender :radio');       // selección universal implícita
$('.gender *:radio');      // misma forma, pero de forma explícita
$('.gender input:radio');  // mucho mejor

9.6. Utilizar la delegación de eventos

La delegación de eventos permite vincular un controlador de evento a unelemento contenedor (por ejemplo, una lista desordenada) en lugar de múltiples elementos contenidos (por ejemplo, los ítems de una lista).jQuery realiza este trabajo fácil a través de $.fn.live y $.fn.delegate. En lo posible, es recomendable utilizar .fn.delegate en lugar de .fn.live, ya que elimina la necesidad de una selección y su contexto explicito reduce la carga en aproximadamente un 80%.
Además, la delegación de eventos permite añadir nuevos elementos contenedores a la página sin tener que volver a vincular sus controladores de eventos.
// mal (si existen muchos items en la lista)
$('li.trigger').click(handlerFn);
 
// mejor: delegación de eventos con $.fn.live
$('li.trigger').live('click', handlerFn);
 
// mucho mejor: delegación de eventos con $.fn.delegate
// permite especificar un contexto de forma fácil
$('#myList').delegate('li.trigger', 'click', handlerFn);

9.7. Separar elementos para trabajar con ellos

En lo posible, hay que evitar la manipulación del DOM. Para ayudar con este propósito, a partir de la versión 1.4, jQuery introduce $.fn.detach el cual permite trabajar elementos de forma separada del DOM para luego insertarlos.
var $table = $('#myTable');
var $parent = $table.parent();
 
$table.detach();
// ... se añaden muchas celdas a la tabla
$parent.append(table);

9.8. Utilizar estilos en cascada para cambios de CSS en varios elementos

Si va a cambiar el CSS en más de 20 elementos utilizando $.fn.css, considere realizar los cambios de estilos añadiéndolos en una etiqueta style. De esta forma se incrementa un 60% el rendimiento.
// correcto hasta 20 elementos, lento en más elementos
$('a.swedberg').css('color', '#asd123');
$('<style type="text/css">a.swedberg { color : #asd123 }</style>')
    .appendTo('head');

9.9. Utilizar $.data en lugar de $.fn.data

Utilizar $.data en un elemento del DOM en lugar de $.fn.data en una selección puede ser hasta 10 veces más rápido. Antes de realizarlo, este seguro de comprender la diferencia entre un elemento DOM y una selección jQuery.
// regular
$(elem).data(key,value);
 
// 10 veces más rápido
$.data(elem,key,value);

No hay comentarios:

Publicar un comentario