EventEmitterの実現


前言
イベントはjsでよく見られます.ブラウザでもnodeでも、このようなイベントのリリース/購読モードの応用はよくあります.発表/購読モードと観察者モードが同じデザインかどうかについては、ここでは具体的な議論はしない.前のプロジェクトでも自分でイベントモジュールを実現したことがあります.コアはまだEventEmitterです.以下はnodeのイベントモジュールと組み合わせて分析します.Event Emitterはどうやって実現するべきですか?注意点がありますか?ソースアドレスhttps://github.com/nodejs/nod...
基礎的な構造と設計
まず第一歩はEventEmitterのクラスです.そして、このクラスの実例的な属性と実例的な方法を考えてみます.実例属性は基本的にeventMapです.空のオブジェクトでもいいです.Object.createを作成してもいいです.maxListenerなどの属性を追加することもできます.実例的な方法として、最も核心的なのはadd delete emitがそれぞれイベントを追加し、イベントを削除し、イベントを発表することです.もちろん実際に実装される場合、例えば、count、has、onece(一括追加)、preAdd(イベントキューの一番前に追加)は、これらの方法は、実際のニーズに応じて追加され得る.
具体的な実現と注意点
以下のコードはすべて簡略化された疑似コードです.
addメソッド
EventEmitter.prototype.add = function(type, fn) {
    if (!isFunction(fn)) return;//                 
    //  type     ,           
    if (this.event[type]) {
        if (isArray(this.event[type])){
            //      preadd push  unshift  
            this.event[type].push(fn);
        } else {
            //      preadd    
            this.event[type] = [this.event[type], fn];
        }
    } else {
        this.event[type] = fn;
    }
}
オンスの方法
nodeのoneceの方法を参考にしてください.
function onceWrapper(...args) {
  if (!this.fired) {
    this.target.removeListener(this.type, this.wrapFn);
    this.fired = true;
    Reflect.apply(this.listener, this.target, args);
  }
}

function _onceWrap(target, type, listener) {
  var state = { fired: false, wrapFn: undefined, target, type, listener };
  var wrapped = onceWrapper.bind(state);
  wrapped.listener = listener;
  state.wrapFn = wrapped;
  return wrapped;
}

EventEmitter.prototype.once = function once(type, listener) {
  this.on(type, _onceWrap(this, type, listener));
  return this;
};
関数はオンセWrapでくるみ、実行前に追加したモニターを削除する必要があります.
delete
いくつかの境界状況を簡単に理解すればいいです.
EventEmitter.prototype.delete = function(type, fn) {
    //        
    if(fn === undefined){
        this.events[type] && delete this.events[type];
    }else{
        //  fn      
        if(this.events[type]) {
            if (this.events[type] === fn) {
                delete this.events[type];
            } else {
                for (var i in this.events[type]) {
                    if(this.events[type][i] === fn){
                        if (i === 0) {
                            this.events[type].shift();
                        } else {
                            this.events[type].splice(i,1);
                        }
                    }
                }
                if(this.events[type].length === 1) this.events[type] = this.events[type][0];
            }
        }
    }
    
}
em it
EventEmitter.prototype.emit = function(type) {
    //    
    var args = [].slice.call(arguments, 1);
    var handler = events[type];

    if (handler === undefined) return false;

    if (typeof handler === 'function') {
        handle.apply(this, args);
    } else {
        var len = handler.length;
        const listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
             handle[i].apply(this, args);
   }
}
イベントのリリースには二つの注意点があります.一つはパラメータの保持に注意し、もう一つはコンテキストであり、ここではイベントのインスタンスのコンテキストを直接取ってもいいし、手動着信コンテキストの形式を考慮してもいいです.あるいはfnは定義の時に直接矢印の関数を書いてもいいし、コンテキストがeventEmitのインスタンスのコンテキストにならないようにしてもいいです.
エラー処理
ここでnodeのイベントのエラーイベントを紹介します.
EventEmitterのインスタンスにエラーが発生すると、'error'イベントがトリガされます.これはNode.jsの中で特殊な状況です.
EventEmitterが'error'イベントのために少なくとも一つのモニターを登録していない場合、'error'イベントがトリガされると、エラーを投げて、スタックを印刷して追跡し、ノード.jsプロセスを終了します.
Node.jsプロセスの崩壊を防ぐために、プロcess対象のuncaught Exceptionイベントにモニターを登録するか、domainモジュールを使用することができます.(domainモジュールは廃棄されました.)
最適な実践としては、常に'error'イベントのためにモニターを登録しなければならない.
自分の実践においても、エラー処理のメカニズムを追加して、イベントインスタンスの安定性を保証することができる.
締め括りをつける
一つのイベントは購読して種類を発表しますが、nodeの中にはたくさんのすごい種類が継承されているイベントがあります.その後、nodeファイルシステムについて勉強します.