面接官:React/VueがEvent Busでコンポーネント通信できる以上、実現できますか.


前言
本文のタイトルのテーマは他の問題から延びてきて、面接の中で面接官の常用のやり方、1つの問題をつかんでずっと深く掘り下げて、この問題が発生する前にきっとこの問題です.
React/Vueの異なるコンポーネント間でどのように通信していますか?
Vue
  • 親子コンポーネント用Props通信
  • 非親子コンポーネント用Event Bus通信
  • プロジェクトが複雑であれば、Vuexなどのグローバル状態管理ライブラリ通信
  • が必要となる場合がある.
  • $dispatch(廃止済み)と$broadcast(廃止済み)
  • React
  • 親子コンポーネント、親->子直接Props、子->親callbackコールバック
  • 非親子コンポーネント、パブリッシュ購読モードのEventモジュール
  • プロジェクトが複雑であればRedux、Mobx等のグローバル状態管理ライブラリ
  • を用いる.
  • 用新しいContext Api
  • 私たちは大体以上の答えを持っています.次に、Event(Bus)をどのように実現するかを聞く可能性があります.これは重要すぎるので、ほとんどのモジュール通信はアンドロイド開発中のEvent Bus、Nodeを含む類似のモードに基づいています.jsにおけるEventモジュール(NodeにおけるほとんどのモジュールはEventに依存する、http、stream、buffer、fs等を含む)
    私たちはNodeのEvent APIに倣って簡単なEventライブラリを実現し、彼はサブスクリプションモードを発表する典型的な応用である.
    事前声明:我々は伝達されたパラメータをタイムリーに判断して誤りを回避せず、核心方法だけを実現した.
    1.基本構造
    1.1 classの初期化
    ES 6のclassキーワードを用いるEventを初期化し、Eventのイベントリストとリスナー上限を含む.
    イベントを格納構造としてMapを選んだが、キー値ペアとしての格納方式Mapが一般のオブジェクトよりも適切であるため、操作もより簡潔であり、まずMapの基本的な使い方と特徴を見ることができる.
    class EventEmeitter {  
         constructor() { 
        this._events = this._events || new Map(); //  /    
        this._maxListeners = this._maxListeners || 10; //     
        }
    }


    1.2傍受とトリガ
    トリガリスニング関数はapplycallの2つの方法を用いることができ、少数のパラメータの場合callの性能がよりよく、複数のパラメータの場合applyの性能がよりよく、その年ノードのEventモジュールは3つのパラメータの下でcallを用いなければapplyを用いる.
    もちろんNodeがES 6+を全面的に抱擁した後、対応するcall/apply操作のReflectの新しいキーワードが書き換えられたが、私たちはそんなに複雑に書きたくないので、簡略化版を作った.
     //     type   
    EventEmeitter.prototype.emit = function(type, ...args){  
             let handler;   //  this._events  
            handler = this._events.get(type); 
           if (args.length > 0) {   
               handler.apply(this, args);  
           }else{ 
              handler.call(this); 
           }  
           return true;
    };
     //  type
    EventEmeitter.prototype.addListener = function(type, fn) {
         //  type fn this._events    
       if (!this._events.get(type)) {  
         this._events.set(type, fn); 
       }
    };


    我々はイベントをトリガするemit方法とイベントを傍受するaddListener方法を実現し、これにより簡単な実践を行うことができる.
    //     const emitter = new EventEmeitter();
    //  arson
    emitter.addListener('arson', man => {  
     console.log(`expel ${man}`); 
    });
     //  arson ,  
    emitter.emit('arson', 'low-end'); // expel low-end


    基本的なトリガ/リスニングを実現したようですが、複数のリスニング者がいたら?
    //           
     emitter.addListener('arson', man => { 
       console.log(`expel ${man}`);
    }); 
    emitter.addListener('arson', man => { 
      console.log(`save ${man}`); 
    }); 
    emitter.emit('arson', 'low-end'); // expel low-end


    はい、最初のトリガしかありませんので、改造する必要があります.
    2.アップグレード改造
    2.1リスニング/トリガのアップグレード
    我々のaddListenerの実現方法はまだ健全ではなく、最初のリスナーをバインドした後、後続のリスナーをバインドすることができないため、後続のリスナーと最初のリスナー関数を1つの配列に配置する必要がある.
    //     type    
    EventEmeitter.prototype.emit = function(type, ...args) { 
      let handler; 
      handler = this._events.get(type);  
      if (Array.isArray(handler)) { 
      //                ,              
          for (let i = 0; i  0) {   
                  handler[i].apply(this, args);  
              } else {      
                      handler[i].call(this);   
              }  
            }  
     } else {
      //                 
          if (args.length > 0) {   
                   handler.apply(this, args);  
              } else {   
                handler.call(this); 
          }  
      }  
       return true;
     };
      //     type   
    EventEmeitter.prototype.addListener = function(type, fn) { 
         const handler = this._events.get(type); 
         //                
          if (!handler) {   
           this._events.set(type, fn);
          } else if (handler && typeof handler === 'function') { 
             //   handler               
              this._events.set(type, [handler, fn]); 
              //                 
          } else {  
             handler.push(fn);
              //         ,        push     
          }
    };

    はい、これからは複数の傍受者の関数を楽しくトリガーすることができます.
    //          
    emitter.addListener('arson', man => { 
            console.log(`expel ${man}`);
     }); 
    emitter.addListener('arson', man => { 
        console.log(`save ${man}`);
     }); 
    emitter.addListener('arson', man => { 
       console.log(`kill ${man}`);
     }); 
     //      
     emitter.emit('arson', 'low-end'); //expel low-end //save low-end //kill low-end

    2.2リスニングの削除removeListener関数で傍受関数を除去しますが、匿名関数は削除できません.
    EventEmeitter.prototype.removeListener = function(type, fn) {  
     const handler = this._events.get(type); //               
       //      ,           
     if (handler && typeof handler === 'function') {   
       this._events.delete(type, fn);  
      }else{   
        let postion;     //   handler   ,                   
         for (let i = 0; i  
      

    3.

    Event , , Event , .

    1. : , .

    2. : removeAllListeners , newListener , , .

    , Event , - , , Event.

    Event , 300 , , , Event .


    : 96
    :https://juejin.im/post/5ac2fb886fb9a028b86e328c