Menu
CoddyTech

イベントエミッター

CoddyのNode.jsジャーニー「Node.jsの基礎」セクションの一部。レッスン 29/33。

ストアは、誰が聞きたがっているかを知らなくても、ノートが追加されたことを通知できるようにします。

node:events の EventEmitter は、イベント名ごとにリスナーの一覧を保持します。on(name, fn) はリスナーを追加し、emit(name, ...args) はその名前のすべてのリスナーを、渡された引数とともに即座に呼び出します。emitの後に追加されたリスナーには何も通知されません。

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 が入ってきて、その後 Ding!

new EventEmitter() はエミッターを作成します。エミッターとは、on と emit を持つオブジェクトです。既存のオブジェクトにこれらのメソッドを持たせるには、そのプロパティを新しいエミッターにコピーします。Object.assign(new EventEmitter(), { notes: [] }) は、notes も持つエミッターを返します。

challenge icon

チャレンジ

簡単

このステップでは、Timers のプロジェクトファイル(notes.js を含む)ではなく、コースで用意されたメモ用コマンドラインツールのプロジェクトを開きます。前の作業は、前のレッスンにそのまま残っています。store.js を編集する前に、提供されたファイルを読んでください。このコピーには、メモ用コマンドと非同期ファイルヘルパーが含まれています。

ストアは新しいメモが追加されるたびに通知し、それに対して何をするかはほかのコードに任せます。ストアをイベントエミッターにしましょう。

  1. store.js で、store を、独自のプロパティとメソッドをすべて保持する EventEmitter にします。node:events から EventEmitter をインポートします。new EventEmitter() は新しい空のエミッターを作成します。レッスンで示されているように、Object.assign を使ってストアのオブジェクトをそのエミッターにコピーします。
  2. store.js の add で、メモを保存した後に、2つの値(メモのテキストと番号)を含む added イベントを発行します。
  3. notes.js で、ストアの added イベントをリッスンします。リスナーは Saved note 、番号、ピリオドを表示します。add がイベントを発行するときにすでにリッスンしているよう、コマンドが実行される前に、ファイルの上部付近でリスナーを設定します。add 分岐自体は何も表示せず、store.add を呼び出すだけです。

node notes.js add Buy bread を実行すると、新しいメモの番号を含む次のような1行が表示されます。

Saved note 3.

clear の後に add Buy milk を実行すると Saved note 1. が表示され、add Call Ada を実行すると Saved note 2. が表示されます。

試してみましょう: $ node notes.js の後の入力欄に add Buy bread と入力し、Enter キーを押します。リスナーによって表示された Saved note と新しい番号が確認できます。次に、clear、add Buy milk、add Call Ada と入力します。Saved note 1.、続いて Saved note 2. が表示されます。

自分で試してみよう

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 icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Node.jsの基礎のすべてのレッスン

自分で練習してみよう: Expressプレイグラウンド