In JavaScript, an event is simply an indication that something has occurred. This allows our code to respond dynamically to various situations. For example:
- A user presses a key.
- A timer ends.
- A signal is received from an API.
Events are a simple mechanism for asynchronous programming, as they allow us to manage tasks in a non-blocking way.
Event management is slightly different depending on whether it is done in a browser or in a runtime like Node.js.
The concepts are the same, but the syntax is somewhat different. We will see this in the article.
Event handler functions
An event handler function is a function that is executed when an event occurs.
For it to work, we need to associate an event handler function with an event emitter.
To do this, we use the method:
- In the browser
addEventListener
- In Node.js
on
// Bind a handler with `addEventListener`
myEmitter.addEventListener("myEvent", (event) => {
console.log("Handling the event:", event);
});
How to trigger an event in JavaScript
Triggering an event, also known as emitting an event, involves creating an instance of the event and firing it on a specific object.
JavaScript provides several ways to do this. The most common method to trigger events in JavaScript is
- In the browser,
dispatchEvent
. - In Node.js,
emit
.
// Create a standard event
let event = new Event("myEvent");
// Fire the event
document.dispatchEvent(event);
In this example:
- We create an event called
myEvent
. - We use
dispatchEvent
to trigger it, thus activating the associated handler.
Basic example
Let’s see how to combine event emission with the handler function, with some complete examples.
In the browser
In the browser, events are fundamental for interacting with the user interface. For example, you can listen for events like click
, submit
, or keydown
on HTML elements and react to them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Events in the Browser</title>
</head>
<body>
<button id="myButton">Click here</button>
<script>
// Select the button
let button = document.getElementById("myButton");
// Add a handler for the 'click' event
button.addEventListener("click", () => {
console.log("The button was clicked");
});
</script>
</body>
</html>
In this example:
- The
click
event is used to detect when the user clicks on a button.
Using events in Node.js
Node.js includes the events
module, which provides the EventEmitter
class, allowing you to register handlers and emit events.
import { EventEmitter } from "events";
// Class that simulates being a server
class Server extends EventEmitter {
start() {
console.log("Server started");
this.emit("serverStarted"); // emits an event on start
}
}
// Create an instance of the server
const server = new Server();
// Register handler for the event
server.on("serverStarted", () => {
console.log("The server is ready to receive requests");
});
// Simulate server execution
server.start();
Here:
- We create an event emitter with
EventEmitter
. - We register a handler for the
myEvent
event usingon
. - We use the
emit
method to trigger the event and pass a message as an argument.
Defining custom events
In addition to handling predefined events, we can create custom events. This is useful in complex projects because we can provide more information than with generic events.
To create our own events, we can use the Event
or CustomEvent
classes.
Event
Event
is a very simple class that allows us to add a message (optional) to identify the event.
// Create a custom event
let customEvent = new Event("myEvent");
// Fire the event
document.dispatchEvent(customEvent);
CustomEvent
CustomEvent
extends the capabilities of the standard event, allowing you to pass additional data when emitting the event.
// Create a custom event with additional data
let customEvent = new CustomEvent("myCustomEvent", {
detail: { message: "Hello from a custom event" },
});
// Assign a handler to receive the data
document.addEventListener("myCustomEvent", (e) => {
console.log(e.detail.message); // Access the custom data
});
// Fire the event
document.dispatchEvent(customEvent);
In this case, we use the detail
property to include additional information that handlers can process.
Integrating events with promises
Sometimes, you may want to integrate event handling with Promises. This is useful for synchronizing asynchronous tasks.
function waitForEvent(event) {
return new Promise((resolve) => {
document.addEventListener(event, resolve, { once: true });
});
}
async function main() {
console.log("Waiting for event...");
await waitForEvent("myEvent");
console.log("Event received.");
}
// Execute and simulate the event
main();
document.dispatchEvent(new Event("myEvent"));
Here, the waitForEvent
function converts an event into a Promise, which allows waiting for its resolution within an asynchronous function.
Internal workings
Under the hood, JavaScript is a single-threaded execution language, which means that it can only execute one task at a time.
When an event occurs, the main flow of the program is not interrupted. Instead, the action associated with the event is registered in the event queue.
The event loop takes care of processing the tasks in this queue when the main thread is free.