イベントエミッター
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 も持つエミッターを返します。
チャレンジ
簡単このステップでは、Timers のプロジェクトファイル(notes.js を含む)ではなく、コースで用意されたメモ用コマンドラインツールのプロジェクトを開きます。前の作業は、前のレッスンにそのまま残っています。store.js を編集する前に、提供されたファイルを読んでください。このコピーには、メモ用コマンドと非同期ファイルヘルパーが含まれています。
ストアは新しいメモが追加されるたびに通知し、それに対して何をするかはほかのコードに任せます。ストアをイベントエミッターにしましょう。
store.jsで、storeを、独自のプロパティとメソッドをすべて保持するEventEmitterにします。node:eventsからEventEmitterをインポートします。new EventEmitter()は新しい空のエミッターを作成します。レッスンで示されているように、Object.assignを使ってストアのオブジェクトをそのエミッターにコピーします。store.jsのaddで、メモを保存した後に、2つの値(メモのテキストと番号)を含むaddedイベントを発行します。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;
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
Node.jsの基礎のすべてのレッスン
自分で練習してみよう: Expressプレイグラウンド