dayonehk.com

Understanding Event-Driven Architecture in Node.js

Written on

Node.js operates primarily on an asynchronous event-driven architecture. Its core APIs function reactively, where events are emitted by an emitter, triggering callback functions linked through listeners specific to those events.

This article delves into the event-driven programming model within a Node.js application.

Event-Driven Logic in Action

Let’s examine an example that demonstrates how to read data from a file:

const fs = require('fs');

const textStream = fs.createReadStream('data.txt', 'utf-8');

textStream.on('readable', () => {

console.log(textStream.read());

});

textStream.on('end', () => console.log('File Read Completed'));

The textStream object, created by fs.createReadStream, acts as an emitter that generates various named events as they occur.

For instance, when the file content is ready to be read, a readable event is triggered. A listener is attached to this event using the on method of the textStream object.

Upon the emission of the readable event, the attached callback logs the file's content, showcasing the asynchronous, event-driven nature of the code.

When the end of the file is reached, an end event is emitted, invoking its associated callback.

A discernible pattern emerges: actions taken by users or the system emit events, which are then captured by listeners. The callbacks define the actions to take when specific events are triggered by the system.

Creating Custom Events

Custom events can be generated in Node.js by instantiating the EventEmitter class:

const EventEmitter = require('events');

const customEvent = new EventEmitter();

Listeners can be added to our custom events as follows:

customEvent.on('my_custom_event', (data) => {

console.table(data);

});

The on method of the customEvent object attaches listeners to specified events.

Listeners are typically added to the end of the listener array for an event. However, if a listener callback should execute before any others, the prependListener method can be utilized.

Finally, we can emit our custom events like this:

customEvent.emit('my_custom_event', {

key1: 'val1',

key2: 'val2',

});

The emit method takes the event name as its first argument, followed by any additional parameters:

emitter.emit(eventName, [...args]);

One-Off Listeners

Listeners can also be designed to trigger only once upon the emission of an event. This is achievable via the once method on the custom event instance:

customEvent.once('my_custom_event', (data) => {

console.table(data);

});

This setup ensures that the listener callback is executed only during the first emission of the my_custom_event, ignoring subsequent emissions.

Workflow Management Using an Event-Driven Pattern

The event-driven approach can also facilitate a pattern for managing workflow states, including error states, through the emitter-listener model.

Consider a fictional delivery status check:

const checkDeliveryStatus = () => {

// Random for demonstration purposes.

const induceSystemError = Boolean(Math.round(Math.random()));

const isDeliverySuccessful = Boolean(Math.round(Math.random()));

if (induceSystemError) {

const systemError = new Error(DELIVERY_STATES.ERRORED.message);

systemError.eventToTrigger = DELIVERY_STATES.ERRORED.eventToTrigger;

throw systemError;

}

return isDeliverySuccessful

? DELIVERY_STATES.SUCCESS : DELIVERY_STATES.FAILURE;

};

The possible delivery states for our workflow could be defined as follows:

const DELIVERY_STATES = {

SUCCESS: {

message: 'The delivery was successful',

eventToTrigger: 'dlvry_success',

},

FAILURE: {

message: 'Delivery attempt failed',

eventToTrigger: 'dlvry_failed',

},

ERRORED: {

message: 'System error occurred',

eventToTrigger: 'dlvry_error',

},

};

Next, let's review the computing logic:

const deliveryEvent = new EventEmitter();

deliveryEvent.on(DELIVERY_STATES.ERRORED.eventToTrigger, ({ message }) => {

console.error(message);

});

deliveryEvent.on(DELIVERY_STATES.FAILURE.eventToTrigger, ({ message }) => {

console.warn(message);

});

deliveryEvent.on(DELIVERY_STATES.SUCCESS.eventToTrigger, ({ message }) => {

console.info(message);

});

try {

const deliveryStatus = checkDeliveryStatus();

const { message, eventToTrigger } = deliveryStatus;

deliveryEvent.emit(eventToTrigger, { message });

} catch (error) {

const {

message = 'Unknown Error Occurred',

eventToTrigger = DELIVERY_STATES.ERRORED.eventToTrigger,

} = error;

deliveryEvent.emit(eventToTrigger, { message });

}

Running this several times (due to the randomness incorporated in our demo logic) reveals that all three system states are effectively managed through our event-based logic.

This is a simplified example to illustrate the workflow management pattern via an event-driven system designed to handle errors effectively.

Conclusion

In conclusion, we have explored the concept of event-driven programming and its implementation in Node.js. This pattern is particularly effective in asynchronous environments and workloads.

In a single-threaded language like JavaScript, properly employing this pattern can help prevent the inadvertent creation of thread-blocking logic.

Thank you for your attention, and I hope you found this information valuable. Cheers :)

In Plain English

Thank you for being part of our community! Before you leave:

  • Don't forget to **clap* and follow the author! ?*
  • Discover more content at **PlainEnglish.io* ?*
  • Sign up for our **free weekly newsletter*. ??*
  • Follow us on: **Twitter* (X), LinkedIn, YouTube, Discord.*
  • Explore our other platforms: **Stackademic*, CoFeed, Venture.*

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Understanding Heart Rate Variability: Eight Key Health Indicators

Explore eight vital health indicators linked to heart rate variability and its implications for well-being.

Navigating Relationships: The Power of Empathy in Communication

Understanding and respecting others' feelings can transform your relationships. Here's how empathy plays a crucial role.

Mastering Dropdowns in React Development with React Suite

Explore how to efficiently implement dropdowns using the React Suite library in your React applications.

The Enduring Medical Myth: Vaccines and Autism

An exploration of the lasting impact of Wakefield's discredited study linking vaccines and autism.

Overcoming Procrastination: Strategies for the 50+ Mindset

Discover effective strategies to combat procrastination, especially for those over 50, and turn challenges into strengths.

The Inaccuracy of Solar and Laser Power Meters in Light Measurement

Exploring why solar and laser power meters fail to accurately measure light intensity from red light therapy devices.

Navigating the Chaos of a Writer's Mind: Insights and Inspirations

Explore the chaotic thoughts of writers on various topics and their unique perspectives on life, technology, and creativity.

Unlocking the Healing Powers of Water Therapy for Wellness

Discover how water therapy enhances health and wellness through various methods and practices.