2012-03-14 13 views
17

Por ahora la mayoría de la gente en este sitio son probablemente consciente de que:¿Por qué no llevar la delegación de eventos Javascript al extremo?

$("#someTable TD.foo").click(function(){ 
    $(e.target).doSomething(); 
}); 

va a realizar mucho peor que:

$("#someTable").click(function(){ 
    if (!$(e.target).is("TD.foo")) return; 
    $(e.target).doSomething(); 
}); 

Ahora cuánto peor, por supuesto, depende de la cantidad de touchdowns su mesa tiene, pero este principio general debería aplicarse siempre y cuando tengas al menos algunos TD. (NOTA: Por supuesto, lo más inteligente sería usar el delegado de jQuery en lugar de lo anterior, pero solo estaba tratando de hacer un ejemplo con una diferenciación obvia).

De todos modos, expliqué este principio a un compañero de trabajo, y su respuesta fue "Bueno, para los componentes de todo el sitio (por ejemplo, una entrada de selección de fecha) ¿por qué detenerse? ¿Por qué no vincular un solo manejador para cada tipo de componente para el CUERPO mismo? " No tuve una buena respuesta.

Obviamente, usar la estrategia de delegación significa replantearse cómo se bloquean los eventos, por lo que es una desventaja. Además, hipotéticamente podría tener una página donde tenga un "TD.foo" que no debería tener un evento conectado. Pero, si comprende y está dispuesto a trabajar en torno al cambio burbujeante del evento, y si aplica una política de "si coloca .foo en un TD, SIEMPRE va a conectar el evento", ninguno de estos parece una Vaya cosa.

Creo que me debe estar perdiendo algo, así que mi pregunta es: ¿hay algún otro inconveniente al solo delegar todos los eventos de todos los componentes del sitio al BODY (en lugar de vincularlos directamente a los elementos HTML involucrados? , o delegándolos a un elemento padre que no sea BODY)?

+0

Creo que es una cuestión de preferencia y un escenario de caso por caso . Lo que quiero decir es que primero debes escribir el código para que sea lo más legible posible. De esta manera, usted u otra persona puede entrar y examinar el código más tarde y pasarlo bien con él. Una vez que haya hecho eso, puede verificar que el código tenga un buen rendimiento y optimizarlo según sea necesario. En su escenario específico, $ ("someTable TD.foo") es más fácil de leer, administrar y seguir que el escenario con un retorno. Alguien podría leer el otro código y malinterpretarlo, causando que introduzca errores con sus cambios. Solo mi opinión – evasilchenko

+0

Estoy totalmente de acuerdo: los desarrolladores deben diseñar primero, sin preocuparse por la optimización, y optimizar solo más adelante según corresponda. Sin embargo, todo esto surgió de la necesidad de la vida real de optimizar un diseño existente (teníamos una gran página hasta que nuestros clientes decidieron usarlo con miles y miles de filas), así que estábamos tratando de encontrar la mejor estrategia. para manejar esa optimización. – machineghost

+1

posible duplicado de [¿Deberían vincularse todos los eventos de jquery a $ (documento)?] (Http://stackoverflow.com/q/12824549/1048572) – Bergi

Respuesta

20

Lo que hace falta es que hay diferentes elementos del rendimiento.

Su primer ejemplo tiene un peor rendimiento al configurar el controlador de clics, pero tiene un mejor rendimiento cuando se desencadena el evento real.

Su segundo ejemplo funciona mejor cuando se configura el controlador de clics, pero su rendimiento es significativamente peor cuando se desencadena el evento real.

Si todos los eventos se pusieran en un objeto de nivel superior (como el documento), entonces tendría una enorme lista de selectores para verificar cada evento con el fin de encontrar qué función de controlador usar. Este mismo es el motivo por el cual jQuery desaprobó el método .live() porque busca todos los eventos en el documento y cuando hubo muchos manejadores de eventos .live() registrados, el rendimiento de cada evento fue malo porque tuvo que comparar cada evento con lotes y muchos selectores para encontrar el controlador de eventos apropiado para ese evento. Para el trabajo a gran escala, es mucho, mucho más eficiente vincular el evento lo más cerca posible del objeto real que desencadenó el evento. Si el objeto no es dinámico, vincula el evento directamente al objeto que lo desencadenará. Esto puede costar un poco más de CPU cuando se vincula por primera vez el evento, pero el desencadenante real del evento será rápido y se escalará.

jQuery's .on() y .delegate() se puede utilizar para esto, pero se recomienda que encuentre un objeto ancestro que esté lo más cerca posible del objeto desencadenante. Esto evita la acumulación de muchos eventos dinámicos en un objeto de nivel superior y evita la degradación del rendimiento para el manejo de eventos.

En el ejemplo anterior, es perfectamente razonable para hacerlo:

$("#someTable").on('click', "td.foo", function(e) { 
    $(e.target).doSomething(); 
}); 

que le daría una representación compacta de un controlador de clic para todas las filas y se seguirá trabajando incluso cuando haya agregado/filas eliminadas.

Pero, esto no tendría tanto sentido:

$(document).on('click', "#someTable td.foo", function(e) { 
    $(e.target).doSomething(); 
}); 

porque esto sería la mezcla de los eventos de mesa con todos los otros eventos de alto nivel en la página cuando no hay una verdadera necesidad de hacerlo. Solo está solicitando problemas de rendimiento en el manejo de eventos sin ningún beneficio de manejar los eventos allí.

Creo que la respuesta breve a su pregunta es que manejar todos los eventos en un lugar de nivel superior genera problemas de rendimiento cuando se desencadena el evento ya que el código tiene que determinar qué manejador debe recibir el evento cuando hay un muchos eventos se manejan en el mismo lugar. Manejar los eventos lo más cerca posible del objeto generador hace que el manejo del evento sea más eficiente.

+1

Gracias por esa explicación detallada. En el caso que estábamos viendo (una tabla con decenas de miles de TD), el rendimiento del evento de conexión fue el cuello de botella, pero su explicación me ayudó a comprender que en muchos otros casos relevantes en nuestro sitio el rendimiento de la resolución del evento importará más que el evento el rendimiento de la conexión (y el enlace excesivo al documento tendría un impacto negativo en el rendimiento de la resolución). Entonces ... no vamos a ser globalmente vinculantes todo ahora :-) – machineghost

3

Si lo hacía en JavaScript, el impacto de los clics aleatorios en cualquier parte de la página desencadenando eventos es casi nulo. Sin embargo, en jQuery la consecuencia podría ser mucho mayor debido a la cantidad de comandos JS sin procesar que debe ejecutar para producir el mismo efecto.

Personalmente, considero que una pequeña delegación es buena, pero una gran parte de ella comenzará a causar más problemas de los que resuelve.

3
  • Si elimina un nodo, los oyentes correspondientes no se eliminan automáticamente.
  • Algunos eventos simplemente no burbuja
  • diferentes bibliotecas pueden romper el sistema deteniendo la propagación de eventos (supongo que usted ha mencionado que uno)
Cuestiones relacionadas