Menu
CoddyTech

Event Emitters

Part of the Node.js Basics section of Coddy's Node.js journey. Lesson 29 of 33.

The store should announce that a note was added without knowing who wants to hear it.

An EventEmitter from node:events keeps a list of listeners for each event name. on(name, fn) adds a listener; emit(name, ...args) calls every listener for that name, straight away, with those arguments. A listener added after the emit hears nothing.

import { EventEmitter } from 'node:events';

const door = new EventEmitter();
door.on('open', (who) => console.log(`${who} came in`));
door.on('open', () => console.log('Ding!'));
door.emit('open', 'Ada');
// Ada came in, then Ding!

new EventEmitter() creates an emitter, an object that has on and emit. To give an existing object those methods, copy its properties onto a new emitter: Object.assign(new EventEmitter(), { notes: [] }) returns an emitter that also has notes.

challenge icon

Challenge

Easy

This step opens the course’s prepared notes command-line tool project, rather than your project files from Timers (including notes.js). Your earlier work stays in its own lesson. Read the supplied files before editing store.js. This copy contains the notes commands and asynchronous file helpers.

The store should announce each new note, and let other code decide what to do about it. Turn the store into an event emitter.

  1. In store.js, make store an EventEmitter that keeps all its own properties and methods. Import EventEmitter from node:events. new EventEmitter() creates a new, empty emitter. Copy the store's object onto that emitter with Object.assign, as the lesson shows.
  2. In store.js, in add, after the notes are saved, emit an added event with two values: the note's text and its number.
  3. In notes.js, listen for added on the store. The listener prints Saved note , the number, and a full stop. Attach it near the top, before the commands run, so it is already listening when add emits. The add branch itself prints nothing now; it only calls store.add.

node notes.js add Buy bread prints one line with the new note's number, such as:

Saved note 3.

After clear, add Buy milk prints Saved note 1., and add Call Ada prints Saved note 2..

Try it: type add Buy bread in the box after $ node notes.js and press Enter. You see Saved note and the new number, printed by your listener. Then type clear, add Buy milk and add Call Ada: you see Saved note 1., then Saved note 2..

Try it yourself

import { existsSync } from 'node:fs';
import { readFile, writeFile } from 'node:fs/promises';

const file = 'notes.json';

const readJson = async (name, fallback) => {
    if (!existsSync(name)) {
        return fallback;
    }
    try {
        return JSON.parse(await readFile(name, 'utf8'));
    } catch (err) {
        console.error(`${name} is damaged: ${err.message}`);
        process.exit(1);
    }
};

const [notes, settings] = await Promise.all([readJson(file, []), readJson('settings.json', {})]);

const store = {
    notes,
    settings,
    async save() {
        await writeFile(file, JSON.stringify(this.notes, null, 2));
    },
    async add(text) {
        this.notes.push(text);
        await this.save();
        return this.notes.length;
    },
    async remove(n) {
        const [text] = this.notes.splice(n - 1, 1);
        await this.save();
        return text;
    },
};

export default store;
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Node.js Basics

Practice on your own: Express playground