En JavaScript un evento es simplemente un indicador de que algo ha ocurrido. Esto permite que nuestro código responda dinámicamente a diversas situaciones. Por ejemplo:
- Un usuario presiona una tecla.
- Un temporizador termina.
- Se recibe una señal desde una API.
Los eventos son un mecanismo sencillo para la programación asíncrona, ya que nos permite gestionar tareas de forma no bloqueante.
La gestión de eventos es ligeramente diferente en función de que se haga en un navegador, o en un runtime como Node.js.
Los conceptos son los mismos, pero la sintaxis es algo diferente. Lo iremos viendo en el artículo.
Funciones manejadoras de eventos
Una función manejadora de eventos (event handler) es una función que se ejecuta en cuando ocurre un evento.
Para que funcione, tenemos que asociar una función manejadora de eventos con un emisor de eventos.
Para ello se emplea el método:
- En el navegador
addEventListener
- En Node.js
on
// Vincular un manejador con `addEventListener`
miEmisor.addEventListener("miEvento", (evento) => {
console.log("Manejando el evento:", evento);
});
Cómo lanzar un evento en JavaScript
Lanzar un evento, también conocido como emitir un evento, implica crear una instancia del evento y desencadenarlo en un objeto específico.
JavaScript proporciona varias formas de hacerlo. El método más común para lanzar eventos en JavaScript es
- En el navegador,
dispatchEvent
. - En Node.js,
emit
.
// Crear un evento estándar
let evento = new Event("miEvento");
// Disparar el evento
document.dispatchEvent(evento);
En este ejemplo:
- Creamos un evento llamado
miEvento
. - Utilizamos
dispatchEvent
para lanzarlo, activando así el manejador asociado.
Ejemplo básico
Veámoslo como juntar la emisión de Eventos, junto a la función manejadora, con unos ejemplos completos
En el navegador
En el navegador, los eventos son fundamentales para interactuar con la interfaz de usuario. Por ejemplo, puedes escuchar eventos como click
, submit
o keydown
en elementos HTML y reaccionar a ellos.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Eventos en el Navegador</title>
</head>
<body>
<button id="miBoton">Haz clic aquí</button>
<script>
// Seleccionar el botón
let boton = document.getElementById("miBoton");
// Agregar un manejador para el evento 'click'
boton.addEventListener("click", () => {
console.log("El botón fue clickeado");
});
</script>
</body>
</html>
En este ejemplo:
- El evento
click
se utiliza para detectar cuando el usuario hace clic en un botón.
Uso de eventos en Node.js
Node.js incluye el módulo events
, que proporciona la clase EventEmitter
, que permite registrar manejadores y emitir eventos.
import { EventEmitter } from "events";
// Clase que simula ser un servidor
class Servidor extends EventEmitter {
iniciar() {
console.log("Servidor iniciado");
this.emit("servidorIniciado"); // emite un evento al iniciar
}
}
// Crear una instancia del servidor
const servidor = new Servidor();
// Registrar handler del evento
servidor.on("servidorIniciado", () => {
console.log("El servidor está listo para recibir solicitudes");
});
// Simular la ejecución del servidor
servidor.iniciar();
Aquí:
- Creamos un emisor de eventos con
EventEmitter
. - Registramos un manejador para el evento
miEvento
usandoon
. - Utilizamos el método
emit
para lanzar el evento y pasar un mensaje como argumento.
Definiendo eventos personalizados
Además de manejar eventos predefinidos, podemos crear eventos personalizados. Esto es útil en proyectos complejos, porque podemos dar más información que con eventos genéricos.
Para crear nuestros propios eventos podemos utilizar las clases Event
o CustomEvent
Event
Event
es una clase muy sencilla, que nos deja añadir un mensaje (opcional) para identificar el evento.
// Crear un evento personalizado
let eventoPersonalizado = new Event("miEvento");
// Disparar el evento
document.dispatchEvent(eventoPersonalizado);
CustomEvent
CustomEvent
extiende las capacidades del evento estándar, permitiendo pasar datos adicionales en el momento de emitir el evento.
// Crear un evento personalizado con datos adicionales
let eventoPersonalizado = new CustomEvent("miEventoPersonalizado", {
detail: { mensaje: "Hola desde un evento personalizado" },
});
// Asignar un manejador que reciba los datos
document.addEventListener("miEventoPersonalizado", (e) => {
console.log(e.detail.mensaje); // Accede a los datos personalizados
});
// Disparar el evento
document.dispatchEvent(eventoPersonalizado);
En este caso, usamos la propiedad detail
para incluir información adicional que los manejadores pueden procesar.
Integrando eventos con promesas
En ocasiones, puedes querer integrar el manejo de eventos con Promesas. Esto es útil para sincronizar tareas asíncronas.
function esperarEvento(evento) {
return new Promise((resolve) => {
document.addEventListener(evento, resolve, { once: true });
});
}
async function main() {
console.log("Esperando evento...");
await esperarEvento("miEvento");
console.log("Evento recibido.");
}
// Ejecutar y simular el evento
main();
document.dispatchEvent(new Event("miEvento"));
Aquí, la función esperarEvento
convierte un evento en una Promesa, lo que permite esperar su resolución dentro de una función asíncrona.
Funcionamiento interno
Bajo el capó, JavaScript es un lenguaje de ejecución única (single-threaded), lo que significa que solo puede ejecutar una tarea a la vez.
Cuando ocurre un evento, no se interrumpe el flujo principal del programa. En su lugar, la acción asociada al evento se registra en la cola de tareas (event queue).
El event loop (bucle de eventos) se encarga de procesar las tareas de esta cola cuando el hilo principal está libre.