Nodejs のコア API のほとんどは非同期イベント駆動設計に基づいて設計されており、イベントを配布できるすべてのオブジェクトは EventEmitter クラスのインスタンスです。
ご存知のとおり、nodejs は単一のスレッドで実行されるため、nodejs はイベント ポーリングを使用してイベント キュー内のイベント メッセージを継続的にクエリし、イベントに対応するコールバック関数を実行する必要があります。これは、 Windows のメッセージ マッピング メカニズム。より詳細な実装リンクについては、別途情報を参照してください。
以下ではEventEmitterの使い方を紹介します。
1. イベントのリッスンとイベントの配布
EventEmitter インスタンスは、以下に示すように、on または addListener を使用してイベントをリッスンし、emit() メソッドを使用してイベントを配布できます。
const events = require('events'), EventEmitter = events.EventEmitter, util = require('util'); function myEmiter(){ EventEmitter.call(this); }; util.inherits(myEmiter,EventEmitter);//继承EventEmitter类 const myEmitterIns = new myEmiter(); myEmitterIns.on('data',(o)=>{ console.log('receive the data:'+o.a); });
実行結果は次のとおりです:
E:developmentdocumentnodejsdemo>nodeevent-example.js
データを受信します:12. パラメータをイベントリスニングコールバック関数に渡します上記の例からわかるように、emit() メソッドは、コールバック関数に任意のパラメータのセットを渡すことができます。注意すべき点は、this キーワードは、アロー関数を除いて、emit メソッドを呼び出す EventEmiter インスタンスをポイントしていることです。アロー関数内の this は時間バインディングが定義されているため、グローバル this に設定されます。以下に示すように:
class myEmiter extends EventEmitter{}//继承EventEmitter类 const myEmitterIns = new myEmiter(); myEmitterIns.on('data',(o)=>{ console.log('receive the data:'+o.a); }); myEmitterIns.emit('data',{a:1});
実行結果は次のとおりです:
E:developmentdocumentnodejsdemo>nodeevent-example.js
これは通常のコールバック関数内です:myEmiter {
domain: null,_events: { data: [Function ], data1: [Function] },
_eventsCount: 2,_maxListeners: unknown }
this in the arrow callback function:
{}
ここで、arrow 関数でのこれについて説明します。アロー関数が実装できる理由 定義時に this をバインドするのは、アロー関数内に this をバインドする機構がないため、外側のスコープで this を使用するため、コンストラクターとして使用できません。
3. イベントリスナーの実行シーケンス
class myEmiter extends EventEmitter{} const myEmitterIns = new myEmiter(); myEmitterIns.on('data',function(data){ console.log("普通回调函数中this:"); console.log(this); }); myEmitterIns.on('data1',(data1)=>{ console.log("箭头回调函数中this:"); console.log(this); }); myEmitterIns.emit('data',{a:1}); myEmitterIns.emit('data1',{a:1});
実行結果は次のとおりです:
E:developmentdocumentnodejsdemo>node event-example.js
data イベント実行: 4721.401msdata1 イベントが実行を開始しました...
もちろん、以下に示すように、コールバック関数で setTimeout、setImmediate、process.nextTick() などの非同期操作を使用して、非同期効果を実現できます。
class myEmiter extends EventEmitter{} const myEmitterIns = new myEmiter(); myEmitterIns.on('data',function(data){ console.time('data事件执行了'); for(var i = 0 ; i< 100000; i++) for(var j = 0 ; j< 100000; j++) ; console.timeEnd('data事件执行了'); }); myEmitterIns.on('data1',(data1)=>{ console.log("data1事件开始执行..."); }); myEmitterIns.emit('data',{a:1}); myEmitterIns.emit('data1',{a:1});
実行結果は次のとおりです。 E:developmentdocumentnodejsdemo> ノードのevent-example.js
data1イベントが実行されました...dataイベントが実行されました...
4. ワンタイムイベントモニタリング
EventEmiterはイベントをリッスンするために一度使用できます。イベント ハンドラーは 1 回だけトリガーされます。以下に示すように、リスナーがログアウトしているため、イベントは発行後に無視されます。myEmitterIns.on('data',function(data){ setImmediate(()=>{ console.log('data事件执行了...'); }); });
実行結果は次のとおりです。 js
DOM イベント リスニングと同様に、EventEmiter もイベント バインドを解除するためにイベント バインディングを削除できるため、コールバック関数のリスナーは名前付き関数である必要があります。関数が参照型であるため、関数が見つかりません。以下に示すように、関数本体が同じであっても、同じ関数ではありません。
myEmitterIns.once('one',(data)=>{ console.log(data); }); myEmitterIns.emit('one','this is first call!'); myEmitterIns.emit('one','this is second call!');
E:developmentdocumentnodejsdemo>nodeevent-example.js
E:developmentdocumentnodejsdemo>
実行結果からわかるように、data イベントは匿名関数を使用しているため削除されませんが、data1 イベントは正常に実行されます。縛られていない。ここで注意すべき点は、エミットがイベントをトリガーした後、そのイベントにバインドされているすべてのコールバック関数が呼び出されるということです。コールバック関数でremoveListener関数を使用して別のコールバックを削除しても、その後のイベント キューは役に立ちません。コールバックを削除しました。以下に示すように:
myEmitterIns.on('data',function(e){ console.log(e); }); myEmitterIns.removeListener('data',function(e){ console.log(e); }); myEmitterIns.emit('data','hello data!'); function deal(e){ console.log(e); } myEmitterIns.on('data1',deal); myEmitterIns.removeListener('data1',deal); myEmitterIns.emit('data1','hello data1!');
6. イベント リスナーとリスニング関数の数を取得します
指定されたイベントのリスナーの数を取得するには、emiter.listeners(eventName) 関数を使用します。指定されたイベントのすべてのリスナーを取得するために使用されます。 listen 関数は次のように使用されます:function dealData1(e){ console.log('data事件执行了...A'); } myEmitterIns.on('data',function(e){ console.log(e); myEmitterIns.removeListener('data',dealData1);//这里解除dealData1的绑定 }); myEmitterIns.on('data',dealData1); myEmitterIns.emit('data','data事件执行了...B'); /*执行结果为: data事件执行了...B data事件执行了...A */ //再次触发该事件时,dealData1回调已经被解除绑定了 myEmitterIns.emit('data','data事件执行了...'); //data事件执行了... 另外可以使用removeAllListeners()解除所有事件的绑定。
E:developmentdocumentnodejsdemo>nodeevent-example.js
それらは次のとおりです: [ [関数: cbA]、[関数: cbB] ]
7. エミッタ リスナーの最大数を取得および設定します
nodejs は、同じイベントは 10 を超えてはなりません。これは、次のように EventEmitter.defaultMaxListeners プロパティを確認することでわかります。var cbA = ()=>{}, cbB = ()=>{}; var emitter = new myEmiter(); emitter.on('data',cbA); emitter.on('data',cbB); console.log('emitter实例的data事件绑定了%d个回调函数',emitter.listenerCount('data')); console.log('它们是:',emitter.listeners('data'));
emitter は getMaxListeners() メソッドを通じてリスナーの最大数を取得し、最大数を設定します以下に示すように、setMaxListeners(n) メソッドを介してリスナーの数を変更します。
実行結果は次のとおりです:
E:developmentdocumentnodejsdemo>nodeevent-example.js
エミッターイベントリスナーの最大数は: 1
(node:6808) 警告: EventEmitter のメモリリークの可能性が 2 つのデータリスナー
で検出されました。制限を増やすには、エミッター .setMaxListeners() を使用します
上記の結果に示されているように、リスナーの最大数が設定されている場合は、同じイベントのリスナーの最大数を超えないようにすることが最善です。メモリリークの原因となります。