Node.js EventEmitter

Node.js のすべての非同期 I/O 操作は完了時にイベントをイベントキューに送信します。

Node.js 内の多くのオブジェクトはイベントを配信します。net.Server オブジェクトは新しい接続があるたびにイベントをトリガーし、fs.readStream オブジェクトはファイルが開かれたときにイベントをトリガーします。これらのイベントを生成するオブジェクトはすべて events.EventEmitter のインスタンスです。

EventEmitter は、Node.js でイベントを作成、登録、トリガーするためのコアモジュールです。

EventEmitter はイベント駆動型プログラミングの基礎であり、開発者がイベントのパブリッシュ/サブスクライブ機構を簡単に実装するのに役立ちます。


EventEmitter クラス

events モジュールは events.EventEmitter という 1 つのオブジェクトのみを提供します。

EventEmitter の核心は、イベントトリガーとイベントリスナー機能のカプセル化です。

次のようにしてrequire("events");このモジュールにアクセスできます。

インスタンス

// events モジュールを導入
var events = require('events');
// eventEmitter オブジェクトを作成
var eventEmitter = new events.EventEmitter();

EventEmitter オブジェクトは、インスタンス化中にエラーが発生すると error イベントをトリガーします。新しいリスナーが追加されると newListener イベントがトリガーされ、リスナーが削除されると removeListener イベントがトリガーされます。

次に、簡単な例で EventEmitter の使い方を説明します。

インスタンス

//event.js ファイル
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
        console.log('some_event イベントがトリガーされました');
});
setTimeout(function() {
        event.emit('some_event');
}, 1000);

このコードを実行すると、1 秒後にコンソールに次のように出力されます。some_event イベントがトリガーされましたその原理は、event オブジェクトが some_event イベントのリスナーを登録し、setTimeout を使用して 1000 ミリ秒後に event オブジェクトへ some_event イベントを送信すると、some_event のリスナーが呼び出されるというものです。

実行結果は次のとおりです。

$ node event.js 
some_event 事件触发

EventEmitter の各イベントは、イベント名と複数のパラメーターで構成されます。イベント名は文字列で、通常は特定の意味を表します。EventEmitter は各イベントに対して複数のイベントリスナーをサポートしています。

イベントがトリガーされると、そのイベントに登録されたイベントリスナーが順番に呼び出され、イベントパラメーターがコールバック関数の引数として渡されます。

このプロセスを次の例で説明します。

インスタンス

//event.js ファイル
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
        console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
        console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'arg1 パラメータ', 'arg2 パラメータ');

上記のコードを実行すると、結果は次のようになります。

$ node event.js 
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数

上記の例では、emitter は someEvent イベントに 2 つのイベントリスナーを登録し、その後 someEvent イベントをトリガーしました。

実行結果では、2 つのイベントリスナーのコールバック関数が順番に呼び出されていることがわかります。これが EventEmitter の最も簡単な使い方です。

EventEmitter には複数のプロパティがあります。たとえば、onとemit。on関数はイベント関数をバインドするために使用され、emitプロパティはイベントをトリガーするために使用されます。次に、EventEmitter のプロパティの説明を詳しく見ていきましょう。

メソッド

番号メソッド & 説明
1addListener(event, listener)
指定されたイベントにリスナーをリスナー配列の末尾に追加します。
2on(event, listener)
指定されたイベントにリスナーを登録します。文字列 event とコールバック関数を受け取ります。
server.on('connection', function (stream) {
  console.log('someone connected!');
});
3once(event, listener)
指定されたイベントに 1 回限りのリスナーを登録します。つまり、リスナーは最大でも 1 回しかトリガーされず、トリガー後すぐにリスナーが解除されます。
server.once('connection', function (stream) {
  console.log('Ah, we have our first user!');
});
4removeListener(event, listener)

指定されたイベントのリスナーを 1 つ削除します。リスナーはそのイベントに既に登録されているリスナーである必要があります。

これは 2 つのパラメーターを受け取ります。1 つ目はイベント名、2 つ目はコールバック関数名です。

var callback = function(stream) {
  console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
5removeAllListeners([event])
すべてのイベントの全リスナーを削除します。イベントを指定した場合は、指定されたイベントの全リスナーを削除します。
6setMaxListeners(n)
デフォルトでは、EventEmitters はリスナーを 10 個以上追加すると警告メッセージを出力します。setMaxListeners 関数は、リスナーのデフォルト制限数を変更するために使用されます。
7listeners(event)
指定されたイベントのリスナー配列を返します。
8emit(event, [arg1], [arg2], [...])
リスナーの順序で各リスナーを実行します。イベントに登録済みリスナーがある場合は true を返し、それ以外の場合は false を返します。

クラスメソッド

番号メソッド & 説明
1listenerCount(emitter, event)
指定されたイベントのリスナー数を返します。
events.EventEmitter.listenerCount(emitter, eventName) //已废弃,不推荐
events.emitter.listenerCount(eventName) //推荐

イベントリスナーを登録します:

インスタンス

const EventEmitter = require('events');
const myEmitter = new EventEmitter();

// イベントリスナーを登録
myEmitter.on('sayHello', (name) => {
  console.log(`Hello, ${name}!`);
});

// イベントをトリガー
myEmitter.emit('sayHello', 'Alice');

出力:

Hello, Alice!

once() を使用して 1 回限りのイベントを登録します:

myEmitter.once('init', () => {
  console.log('Initialization event occurred');
});

myEmitter.emit('init'); // 打印: Initialization event occurred
myEmitter.emit('init'); // 不会再触发

イベントトリガー時にパラメーターを渡して、リスナーで使用できます:

インスタンス


myEmitter.on('data', (value1, value2) => {
  console.log(`Received values: ${value1}, ${value2}`);
});

myEmitter.emit('data', 'Node.js', 'EventEmitter');
// 出力: Received values: Node.js, EventEmitter

トリガーされたイベントに対応するリスナーがない場合、EventEmitter はエラーをスローします:

インスタンス

myEmitter.on('error', (err) => {
  console.error('Error event triggered:', err);
});

myEmitter.emit('error', new Error('Something went wrong'));
// 出力: Error event triggered: Error: Something went wrong

イベント

番号イベント & 説明
1newListener
  • event- 文字列、イベント名

  • listener- イベントを処理する関数

このイベントは、新しいリスナーが追加されたときにトリガーされます。

2removeListener
  • event- 文字列、イベント名

  • listener- イベントを処理する関数

指定されたリスナー配列から 1 つのリスナーを削除します。この操作により、削除されたリスナーより後ろにあるリスナーのインデックスが変わることに注意してください。

インスタンス

次の例では、connection(接続)イベントを通じて EventEmitter クラスのアプリケーションを示します。

main.js ファイルを作成し、コードは次のとおりです。

インスタンス

var events = require('events');
var eventEmitter = new events.EventEmitter();

// リスナー #1
var listener1 = function listener1() {
   console.log('リスナー listener1 が実行されました。');
}

// リスナー #2
var listener2 = function listener2() {
  console.log('リスナー listener2 が実行されました。');
}

// connection イベントをバインドし、処理関数は listener1
eventEmitter.addListener('connection', listener1);

// connection イベントをバインドし、処理関数は listener2
eventEmitter.on('connection', listener2);

var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 個のリスナーが接続イベントを監視しています。");

// connection イベントを処理
eventEmitter.emit('connection');

// バインドされた listener1 関数を削除
eventEmitter.removeListener('connection', listener1);
console.log("listener1 はもうリッスンされていません。");

// 接続イベントをトリガー
eventEmitter.emit('connection');

eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 個のリスナーが接続イベントを監視しています。");

console.log("プログラムの実行が完了しました。");

上記のコードの実行結果は次のとおりです。

$ node main.js
2 个监听器监听连接事件。
监听器 listener1 执行。
监听器 listener2 执行。
listener1 不再受监听。
监听器 listener2 执行。
1 个监听器监听连接事件。
程序执行完毕。

error イベント

EventEmitter は特別なイベント error を定義しています。これはエラーの意味を含み、例外が発生したときには通常 error イベントをトリガーします。

error がトリガーされたとき、EventEmitter は対応するリスナーがない場合、Node.js はそれを例外として扱い、プログラムを終了してエラーメッセージを出力すると規定しています。

error イベントをトリガーする可能性のあるオブジェクトには、エラーが発生した後にプログラム全体がクラッシュしないように、通常リスナーを設定します。例:

var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.emit('error'); 

実行時に次のエラーが表示されます:

node.js:201 
throw e; // process.nextTick error, or 'error' event on first tick 
^ 
Error: Uncaught, unspecified 'error' event. 
at EventEmitter.emit (events.js:50:15) 
at Object.<anonymous> (/home/byvoid/error.js:5:9) 
at Module._compile (module.js:441:26) 
at Object..js (module.js:459:10) 
at Module.load (module.js:348:31) 
at Function._load (module.js:308:12) 
at Array.0 (module.js:479:10) 
at EventEmitter._tickCallback (node.js:192:40) 

EventEmitter を継承する

ほとんどの場合、EventEmitter を直接使用するのではなく、オブジェクト内でそれを継承します。fs、net、http を含め、イベント応答をサポートするコアモジュールはすべて EventEmitter のサブクラスです。

なぜそうするのでしょうか?理由は 2 つあります:

  • 第一に、何らかの実体機能を持つオブジェクトがイベントを実装するのは意味論に適合し、イベントの監視と発生はオブジェクトのメソッドであるべきです。

  • 第二に、JavaScript のオブジェクト機構はプロトタイプベースであり、部分的な多重継承をサポートしています。EventEmitter を継承しても、オブジェクトの既存の継承関係が崩れることはありません。

ほとんどの Node.js コアモジュール(HTTP、ファイルシステムなど)は EventEmitter を継承しています。独自のクラスを作成して EventEmitter を継承できます。

インスタンス

class MyEmitter extends EventEmitter {}
const customEmitter = new MyEmitter();

customEmitter.on('customEvent', () => {
  console.log('Custom event fired');
});

customEmitter.emit('customEvent');
その他の拡張