Delegación de eventos en Javascript: Un caso práctico
Supongamos que tenemos un blog (
) y queremos que todos los enlaces a páginas fuera de nuestro dominio se abran en una pestaña nueva del navegador. Por desgracia tenemos muchos artículos y no podemos cambiar el atributo target de los enlaces manualmente. ¿Qué hacer? La solución más conveniente es utilizar un poco de Javascript para cambiar el target dinámicamente. Usando jQuery, una posible implementación sería la siguiente:
$(".article-body").find("a").each(function(i, el) {
if($(el).attr("href").indexOf(window.location.hostname) === -1 ) {
$(el).attr("target", "_blank");
}
});
Esta función busca todos los enlaces dentro del elemento con la clase article-body, y para cada uno de ellos, compara con el hostname de nuestra página. Si el enlace pertenece a un sitio distinto, añade el atributo target="_blank" para abrir el enlace en una nueva ventana. ¿Fácil, verdad?
Otra posible solución sería capturar el momento en el que se clica el enlace con el evento onclick, y abrir el enlace en una nueva ventana.
$(".article-body").find("a").each(function(i, el) {
$(this).click(function() {
if($(this).attr("href").indexOf(window.location.hostname) === -1 ) {
window.open($(this).attr("href"));
return false;
}
});
});
También muy fácil. ¿Pero cuál de las 2 opciones es mejor usar? Haciendo un test con una página de prueba con 20000 enlaces (no vamos a quedarnos cortos
), vemos que la primera alternativa tarda unos 200ms de media, mientras que la segunda tarda más de 300ms.
¿Cómo podríamos hacer este código más eficiente? La respuesta es usar lo que se conoce como Delegación de eventos. El concepto de Delegación de eventos en Javascript significa que un evento asociado a un nodo padre (Ej: article-body) puede ser disparado por uno de los nodos hijos (Ej: a), gracias al mecanismo de propagación de eventos en un navegador -de dentro para afuera-. Esto quiere decir que si ocurre un evento, este se va propagando por los nodos ascendentes hasta llegar a la raiz del documento (), puede ser capturado por cualquier elemento de la jerarquía que espere dicho evento. Es un poco difícil de explicar pero una vez que se entiende, se trabaja con ello de forma bastante intuitiva.
Despues del rollo teórico, vamos a reescribir el código usando la función .on() de jQuery, que nos permite usar delegación de eventos de forma sencilla:
$(".article-body").on("click", "a", function(event){
if($(this).attr("href").indexOf(window.location.hostname) === -1 ) {
window.open($(this).attr("href"));
return false;
}
});
Este código tarda apenas ¡2ms! en una página con 20000 enlaces. Esto es posible ya que el evento click se asigna a un único elemento (la capa contenedora article-body), en comparación con el caso anterior, donde se asignan n eventos en una página con n enlaces. De este modo hemos mejorado exponencialmente el rendimiento de nuestra función.
¿Serías capaz de hacer este código aún más eficiente? ¡Explica cómo en los comentarios!


