Un evento es una notificación que describe una ocurrencia del pasado reciente.
Una implementación típica de un sistema controlado por eventos utiliza un despachador de eventos y funciones de manejo (o suscriptores ). El despachador proporciona una API para conectar controladores a eventos (jQuery's bind
) y un método para publicar un evento a sus suscriptores ( trigger
en jQuery). Cuando habla de eventos IO o UI, también suele haber un bucle de eventos , que detecta nuevos eventos, como los clics del mouse, y los pasa al despachador. En JS-land, el navegador proporciona el despachador y el bucle de eventos.
Para el código que interactúa directamente con el usuario, respondiendo a las pulsaciones de teclas y clics, la programación controlada por eventos (o una variación de la misma, como la programación reactiva funcional ) es casi inevitable. Usted, el programador, no tiene idea de cuándo o dónde hará clic el usuario, por lo que depende del marco de la GUI o del navegador detectar la acción del usuario en su bucle de eventos y notificar su código. Este tipo de infraestructura también se usa en aplicaciones de red (cf NodeJS).
Su ejemplo, en el que genera un evento en su código en lugar de llamar a una función directamente, tiene algunas compensaciones más interesantes, que analizaré a continuación. La principal diferencia es que el editor de un evento ( makeItSnow
) no especifica el receptor de la llamada; eso está conectado a otra parte (en la llamada a bind
en su ejemplo). Esto se llama disparar y olvidar : makeItSnow
anuncia al mundo que está nevando, pero no le importa quién está escuchando, qué sucede después o cuándo sucede; simplemente transmite el mensaje y se quita el polvo de sus manos.
Por lo tanto, el enfoque basado en eventos desacopla al remitente del mensaje del receptor. Una ventaja que esto le brinda es que un evento determinado puede tener múltiples controladores. Puede vincular una gritRoads
función a su evento de nieve sin afectar el shovelSnow
controlador existente . Tiene flexibilidad en la forma en que su aplicación está conectada; para desactivar un comportamiento, solo necesita eliminar la bind
llamada en lugar de buscar el código para encontrar todas las instancias del comportamiento.
Otra ventaja de la programación basada en eventos es que le brinda un lugar para plantear inquietudes transversales. El despachador de eventos desempeña el papel de Mediador , y algunas bibliotecas (como Brighter ) utilizan una canalización para que pueda conectar fácilmente los requisitos genéricos, como el registro o la calidad de servicio.
Divulgación completa: Brighter se desarrolla en Huddle, donde trabajo.
Una tercera ventaja de desacoplar el remitente de un evento del receptor es que le brinda flexibilidad cuando maneja el evento. Puede procesar cada tipo de evento en su propio hilo (si su despachador de eventos lo admite), o puede colocar eventos generados en un intermediario de mensajes como RabbitMQ y manejarlos con un proceso asincrónico o incluso procesarlos en masa durante la noche. El receptor del evento podría estar en un proceso separado o en una máquina separada. ¡No tiene que cambiar el código que genera el evento para hacer esto! Esta es la gran idea detrás de las arquitecturas de "microservicios": los servicios autónomos se comunican mediante eventos, con el middleware de mensajería como la columna vertebral de la aplicación.
Para un ejemplo bastante diferente de estilo basado en eventos, mire el diseño controlado por dominio, donde los eventos de dominio se utilizan para ayudar a mantener los agregados separados. Por ejemplo, considere una tienda en línea que recomienda productos basados en su historial de compras. A Customer
debe tener actualizado su historial de compras cuando ShoppingCart
se paga. El ShoppingCart
agregado puede notificar al Customer
mediante un CheckoutCompleted
evento; la Customer
obtendría actualizada en una transacción separada en respuesta al evento.
El principal inconveniente de este modelo basado en eventos es la indirección. Ahora es más difícil encontrar el código que maneja el evento porque no puede navegar hasta él usando su IDE; debe averiguar dónde está vinculado el evento en la configuración y esperar que haya encontrado todos los controladores. Hay más cosas para tener en mente en cualquier momento. Las convenciones de estilo de código pueden ayudar aquí (por ejemplo, colocar todas las llamadas bind
en un archivo). Por el bien de su cordura, es importante usar solo un despachador de eventos y usarlo de manera consistente.
Otra desventaja es que es difícil refactorizar eventos. Si necesita cambiar el formato de un evento, también debe cambiar todos los receptores. Esto se exacerba cuando los suscriptores de un evento están en máquinas diferentes, porque ahora necesita sincronizar las versiones de software.
En ciertas circunstancias, el rendimiento puede ser una preocupación. Al procesar un mensaje, el despachador debe:
- Busque los controladores correctos en alguna estructura de datos.
- Cree una canalización de procesamiento de mensajes para cada controlador. Esto puede involucrar un montón de asignaciones de memoria.
- Llamar dinámicamente a los manejadores (posiblemente usando la reflexión si el lenguaje lo requiere).
Esto es ciertamente más lento que una llamada de función normal, lo que solo implica empujar un nuevo marco en la pila. Sin embargo, la flexibilidad que le brinda una arquitectura basada en eventos hace que sea mucho más fácil aislar y optimizar el código lento. Tener la capacidad de enviar trabajo a un procesador asíncrono es una gran victoria aquí, ya que le permite atender una solicitud de inmediato mientras el trabajo duro se trata en segundo plano. En cualquier caso, si está interactuando con el DB o dibujando cosas en la pantalla, los costos de IO reducirán totalmente los costos de procesamiento de un mensaje. Se trata de evitar la optimización prematura.
En resumen, los eventos son una excelente manera de construir software acoplado libremente, pero no están exentos de costos. Sería un error, por ejemplo, reemplazar cada llamada de función en su aplicación con un evento. Use eventos para hacer divisiones arquitectónicas significativas.
$(document).bind('snow', shovelShow)
. No es necesario envolverlo en una función anónima.