この記事では主にノードのイベントメカニズムを紹介し、EventEmitterクラスの実装アイデアを明確にするために簡単なイベントメカニズムを実装します。
Node.js はイベント駆動型のノンブロッキング I/O モデルを使用しており、軽量かつ効率的です。
nodejs の公式ドキュメントには、node の機能の 1 つがイベントであると明確に書かれています。駆動 (イベント ドライバー) が非常に重要であることがわかります。ソース コードを見ると、そのイベント メカニズムは js で記述された EventEmitter クラスであることがわかります。これは非常にエレガントに記述されており、パブリッシュ/サブスクライブ モデルを適用しています。
パブリッシュ/サブスクライブ モードで単純なイベント メカニズムを実装することで、EventEmitter クラスの実装アイデアを明確にすることができます
Publish/Subscribe (パブリッシュ/サブスクライブ モード)
類似点
はパターン、つまり単語のパターンに関するものです、非常に抽象的に聞こえます。まずは栗をあげましょう。朝、昼、夕刊を発行する新聞組織があるとします。特定の新聞を読みたい場合は、新聞社に購読する必要があります。該当する新聞が発売されると、新聞社から新聞を受け取るように通知されます。
このプロセスにおいて、新聞組織は 2 つの機能を実装しました。1 つは顧客の購読を受け入れることで、もう 1 つはさまざまな種類の新聞を発行することです。新聞が発行されると、その種類の新聞を購読している顧客に通知が届きます。
この新聞組織は私たちが実現したいイベントの仕組みです。
目的
上記の例からわかるように、1. 新聞を発行します。2. 新聞組織の存在により、この継続的なプロセスが最初に購読されます。公開すると、リリース時に自動的に顧客に送信され、アクション時間の分離が実現します。これはパブリッシュ/サブスクライブ システムの利点でもあります。
実装アイデア
3つのイベントに対応した3種類の新聞があり、それぞれのイベントが発生したときに顧客に通知する必要があります。対応するデータ形式は次のとおりです:
var Event = { morning: event1, noon: event2, night: event3 }
各新聞は複数の人が購読している可能性があるため、形式は次のように最適化できます:
var Event = { morning: [e11, e12,...], noon: [e21, e22], night: event3 }
ユーザーが購読すると、イベントは対応する配列に追加され、イベントが解放されると、対応するイベントが実行されます。はっきり言って、保管してから使いましょう。
具体的なコードは次のとおりです:
1.on はサブスクライブを意味し、対応する配列にイベントを追加します
2.emit はパブリッシュを意味し、対応する配列内のデータを実行のために取り出します
3.off は無駄なイベントを削除することを意味します
var Event = { on: function(key, listener) { if (!this.__events) { this.__events = {} } if (!this.__events[key]) { this.__events[key] = []; } if (_indexOf(this.__events[key], listener) == -1 && typeof listener === 'function') { this.__events[key].push(listener) } }, emit: function(key) { if (!this.__events || !this.__events[key]) return //取得每次订阅不同的参数 var arg = Array.prototype.slice.call(arguments, 1) || []; var listeners = this.__events[key]; var len = listeners.length; for (var i=0; i<len; i++) { listeners[i].apply(this, arg) } return this }, off: function(key, listener) { if (!key && !listener) { this.__events = {} } if (key && !listener) { delete this.__events[key] } if (key && listener) { var listeners = this.__events[key]; var index = _indexOf(listeners, listener); (index > -1) && listeners.splice(index, 1); } return this } } var _indexOf = function(array,key){ if (array === null) return -1 var i = 0, length = array.length for (; i < length; i++) if (array[i] === key) return i return -1 } //调用 Event.on('console1', function(num) { console.log(num); // 1 }); Event.emit('console1', 1)
ノードのEventEmitter
ノードのEventEmitterの基本ロジックは、上記の例と基本的に同じですが、より複雑です。
1. イベントを購読する
function _addListener(target, type, listener, prepend) { var m; var events; var existing; if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); events = target._events; ... if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; } else { // If we've already got an array, just append. if (prepend) { existing.unshift(listener); } else { existing.push(listener); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener;
2. イベントを公開する
EventEmitter.prototype.emit = function emit(type) { ... handler = events[type]; switch (len) { // fast cases case 1: emitNone(handler, isFn, this); break; case 2: emitOne(handler, isFn, this, arguments[1]); break; case 3: emitTwo(handler, isFn, this, arguments[1], arguments[2]); break; case 4: emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); break; // slower default: args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; emitMany(handler, isFn, this, args); } }
ここまで述べて、皆さんは EventEmitter の実装アイデアを理解できたと思います。
関連する推奨事項:
以上がノードイベントの仕組みの説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。