Menu
CoddyTech

事件发射器

本课属于 Coddy Node.js 学习旅程的“Node.js 基础”单元。第 29 课,共 33 课。

商店应该在添加笔记后发出通知,但不必知道谁想听到这条通知。

EventEmitter(来自 node:events)会为每个事件名称保存一个监听器列表。on(name, fn) 会添加一个监听器;emit(name, ...args) 会立即调用该名称对应的所有监听器,并传入这些参数。在事件发出后才添加的监听器不会收到通知。

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 中,保存笔记后,发出一个 added 事件,并传入两个值:笔记文本和笔记编号。
  3. 在 notes.js 中,为存储模块上的 added 事件添加监听器。监听器会打印 Saved note 、编号和句号。在靠近文件顶部的位置添加监听器,并放在命令运行之前,这样 add 发出事件时它就已经在监听了。现在,add 分支本身不打印任何内容,只调用 store.add。

node notes.js add Buy bread 会打印一行,其中包含新笔记的编号,例如:

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 在线编辑器