ホームページ > ウェブフロントエンド > jsチュートリアル > Nodejs オブザーバー pattern_node.js についての簡単な説明

Nodejs オブザーバー pattern_node.js についての簡単な説明

WBOY
リリース: 2016-05-16 15:36:49
オリジナル
944 人が閲覧しました

1. はじめに

私はしばらく Nodejs を使用していますが、より高いレベルで使いこなすために、その API を見直し、さらに新しい機能を使用していきます。この API の概要は、英語版の単純な中国語版とは異なります。 . さらなる拡張と独自の拡張を行っていきます。皆さんのお役に立てれば幸いです。コアイベントから始めましょう

Nodejs のイベントは、Nodejs のコアメカニズムをサポートするオブザーバーモードを実装しており、http/fs/mongoose などはすべてイベントを継承し、リスニングイベントを追加できます。この設計パターンは、クライアント側のコンポーネント プログラミングのアイデアでよく使用されます。まず、このパターンを簡単に理解しましょう。

私が初めてオブザーバー パターンに触れたのは、Extjs フレームワークの Ext.util.observable ソース コードでした。当時、私は JS に慣れていなかったので、このパターンが非常に強力であると感じました。私が最初に知ったデザイン パターンは、後に underscore.js のソース コードにも含まれていました。後者のほうがシンプルで洗練されているため、コンポーネントを作成するときは基本的にこの考え方に従います。

オブザーバー モードでは、on('show', callback) などの監視イベントをオブジェクトに追加します。このイベントは、show などの条件を満たしたときにオブジェクトによってトリガーされます。ブラウザ自体が監視を実装しています。ドームの仕組み。

入力にキーアップ監視を追加した場合、その目的はその値を出力することです

$( 'input' ).on( 'keyup', function(){
   console.log( this.value );
} );
ログイン後にコピー

このように内容を入力すると、その値がログに出力されます。

しかし、Dialog などのコンポーネントを作成した場合、最も一般的に使用される表示/非表示イベントをどのように監視できるでしょうか?

基本的なアプローチは、

のように、インスタンス化中にコールバックを直接設定することです。
var dialog = new Dialog({
  content: '这里是弹出框的内容',
  show: function(){
    console.log( '当弹框时输出此段内容' );
  }
});
ログイン後にコピー

これも使用できますが、明らかに柔軟性が不十分です。ダイアログを入力のように作成し、いつでもイベントを追加できるようにするにはどうすればよいですか

2. オブザーバーモードの実装

最初に Events オブジェクトを実装します。これにより、基本的な監視と発行のトリガーが提供され、イベントはオブジェクトの _events に json 形式でスタックされます。

var Events = {
  on: function( name, callback){
    this._events = this._events || {};
    this._events[ name ] = this._events[ name ] || [];
    this._events[ name ].push( callback );
  },
  emit: function( name ){
    this._events = this._events || {};
    var args = Array.prototype.slice.call( arguments, 1 ),
       me = this;
    if( this._events[ name ] ){
      $.each( this._events[ name ], function( k, v ){
        v.call( me, args );
      } )
    }
  }   
}
ログイン後にコピー

オブジェクトの属性をコピーするために別の抽象関数が使用されます

function extend( source ){
  var args = Array.prototype.slice.call( arguments, 1 );
  for( var i = 0, parent; parent = args[i]; i++ ){
    for( var prop in parent ){
      source[ prop ] = parent[ prop ];
    }
  }
}
ログイン後にコピー

ダイアログを実装します。
作成のみを実装します。メソッド: 表示 / 非表示; イベント: 表示 / 非表示;

効果が表示されたら、このスタイルを追加してください

.dialog{
  position: fixed;
  top: 50%;
  left: 50%;
  margin: -50px 0 0 -100px;
  width: 200px;
  height: 120px;
  background: #fff;
  border: 5px solid #afafaf;
}
ログイン後にコピー
コンポーネントを実装する

var Dialog = function( config ){
  this.config = config;
  this.init( this.config );
};
ログイン後にコピー
拡張属性

extend( Dialog.prototype, {

  init: function( config ){
    this.render( config )
  },

  render: function( config ){
    this.el = $( '<div>' ).addClass( 'dialog' );
    this.el.html( config.content );
    $( 'body' ).append( this.el );
  },

  show: function( param ){
    this.el.fadeIn();
    this.emit( 'show', param );
  },

  hide: function( param ){
    this.el.fadeOut();
    this.emit( 'hide', param );
  }

}, Events );

ログイン後にコピー
インスタンスを生成し、それに 3 つの表示イベントと非表示リスニング イベントを追加します

var dialog = window.dialog = new Dialog({
  content: 'dialog one'
});

dialog.on( 'show', function( txt ){
  console.log( 'dialog show one ' + txt );
} );

//do something

dialog.on( 'show', function( txt ){
  console.log( 'dialog show two ' + txt );
} );

//do something

dialog.on( 'show', function( txt ){
  console.log( 'dialog show three ' + txt );
} );

//do something

dialog.on( 'hide', function( txt ){
  console.log( 'dialog hide one ' + txt );
} );

//do something

dialog.on( 'hide', function( txt ){
  console.log( 'dialog hide two ' + txt );
} );

//do something

dialog.on( 'hide', function( txt ){
  console.log( 'dialog hide three ' + txt );
} );

ログイン後にコピー
6 回に分けて 6 つの異なる表示イベントと非表示イベントを追加しました。

Dialog.show() を実行すると、対応する 3 つのログが出力されます。追加されたイベントは、図
に示すように、dialog._events に保存されます。

Nodejs オブザーバー pattern_node.js についての簡単な説明

追加された 3 つのショーはすべて正常に出力され、イベントは _events 属性に保存されます

nodejs Events もこのプロセスを実装します。

3. 構造

var Events = require( 'events' );
console.log( Events );
/*
输出如下数据,可以看出 Events指向其EventEmiter
{ [Function: EventEmitter]
  EventEmitter: [Circular],
  usingDomains: [Getter/Setter],
  defaultMaxListeners: 10,
  init: [Function],
  listenerCount: [Function] }
*/

var myEmitter = new Events();
console.log( myEmitter );
/*
{ domain: null,
  _events: {},   //可以看到实例本身也有_events属性,添加的监听的事件就保存在这里
  _maxListeners: undefined}
*/

console.log( myEmitter.__proto__ );
/*
{ domain: undefined,
  _events: undefined,
  _maxListeners: undefined,
  setMaxListeners: [Function: setMaxListeners],
  emit: [Function: emit],
  addListener: [Function: addListener],
  on: [Function: addListener],
  once: [Function: once],
  removeListener: [Function: removeListener],
  removeAllListeners: [Function: removeAllListeners],
  listeners: [Function: listeners] }
*/

myEmitter.on( 'show', function( txt ){ console.log( 'one ' + txt )})
myEmitter.on( 'show', function( txt ){ console.log( 'tow ' + txt )})
myEmitter.on( 'hide', function( txt ){ console.log( 'one ' + txt )})
myEmitter.emit( 'show', 'show' );
myEmitter.setMaxListeners( 10 );
console.log( myEmitter );
/*
{ domain: null,
  _events: { show: [ [Function], [Function] ], hide: [Function] }, //添加后的事情,以json形式存放
  _maxListeners: 10 }
*/

ログイン後にコピー

4. API

これが提供するメソッドには、addListener の略語が含まれます。その他の属性は、名前が示すとおりです。

property
_events: undefined,   //以压栈形式存放on进来的事件
_maxListeners: undefined  //设置最大监听数,超出提warn

----------------------------------------------------------------------------------------------------------------

method
setMaxListeners: [Function: setMaxListeners], 
/*设置私有属性_maxListeners的值,默认Events会在当某监听事件多于10个时发现警告(见上面Events.defaultMaxListeners),以防止内存泄露,如
(node) warning: possible EventEmitter memory leak detected. 11 show listeners added. Use emitter.setMaxListeners() to increase limit.
但这只是个友好的提醒,可以通过设置最大监听数来规避这个问题
myEmitter.setMaxListeners( 20 );
*/

emit: [Function: emit],
 /*触发监听事件
emitter.emit( event, [arg1], [arg2], ... )
如myEmitter.on( 'show', 'prompt content' );
 参数1为事件名,参数二供on回调里的参数
 */

addListener: [Function: addListener],
 /*
添加监听事件
emitter.addListener( event, listener );
如 myEmitter.addListener( 'show', function( txt ){ console.log( txt ) } );
参数一是事件名,参数二是对应的回调,回调里的参数就是 emit里的arguments.prototype.slice.call(1);
 */

on: [Function: addListener],
 /*
是addListener简写
 */

once: [Function: once],
 /*
作用同 on,不过emit一次后就失效了
emitter.once( event, listener );
如 myEmitter.once( 'show', function( txt ){ console.log( txt ) } );
当myEmitter.emit执行第二次时没有输出
 */

removeListener: [Function: removeListener],
 /*
移除指定事件的指定回调,此时回调不能再用匿名函数。
emitter.removeListener( event, listener );
如 
function show( txt ){ console.log( txt ) };
myEmitter.on( 'show', show );
console.log( myEmitter._events ); 
// { show: [ Function: show ] }
myEmitter.removeListener( 'show', show );  
 console.log( myEmitter._events ); 
// {}
 */

removeAllListeners: [Function: removeAllListeners],
 /*
 删除指定事件的所有回调
 emitter.removeAllListeners( [ event ] );
 如 
  myEmitter.removeAllListeners( 'show' );   //删除所有show监听
  myEmitter.removeAllListeners();   //删除所有监听
 */

listeners: [Function: listeners]
/*
查看指定监听
emitter.listeners( event );
如 myEmitter.listeners( 'show' ); //返回一个数组
同我们前面使用的 myEmitter._events[ 'show' ]
*/

另外Events类本身提供了一个方法
Events.listenerCount( emitter, event ); 获取指定实例下指定监听数
如 Event.listenerCount( myEmitter, 'show' )

-----------------------------------------------------------------------------------------------

还有两个event
newListener / remoteListener,分别应用于为实例添加( on / once )和删除( removeListener ) 操作。
emitter.on( event, listener );
emitter.on( 'newListener', function( event, listener ){
  console.log( emitter.listeners( 'show' ) );   //注意,此时监听还并没有添加到 emitter.listeners
  console.log( arguments );  
 });

 emitter.on( 'removeListener', function(){
  console.log( emitter.listeners( 'show' ) );
  console.log( arguments );
 })

ログイン後にコピー
5. アプリケーション

イベントを使用するには、通常、上記の API セクションに示すように、イベントを直接インスタンス化します

しかし、先ほどの Dialog のように、nodejs 側にもコンポーネントを実装する場合、Dialog に Events の機能も持たせるにはどうすればよいでしょうか? Extjs

で実装できる拡張ソリューション

ダイアログビルダーの作成

var Dialog = function(){
  //do something
}

//抽象apply函数,提供属性的深度复制,同上面的extend
function apply( source ){
  var args = Array.prototype.slice.call( arguments, 1 );
  for( var i = 0, parent; parent = args[i]; i++ ){
    for( var prop in parent ){
      source[ prop ] = parent[ prop ];
    }
  }
}

//抽象extend函数,用于实现继承
var extend = function(){
  // inline overrides
  var io = function(o){
    for(var m in o){
      this[m] = o[m];
    }
  };
  var oc = Object.prototype.constructor;

  return function(sb, sp, overrides){
    if(typeof sp == 'object'){
      overrides = sp;
      sp = sb;
      sb = overrides.constructor != oc &#63; overrides.constructor : function(){sp.apply(this, arguments);};
    }
    var F = function(){},
      sbp,
      spp = sp.prototype;

    F.prototype = spp;
    sbp = sb.prototype = new F();
    sbp.constructor=sb;
    sb.superclass=spp;
    if(spp.constructor == oc){
      spp.constructor=sp;
    }
    sb.override = function(o){
      apply(sb, o);
    };
    sbp.superclass = sbp.supr = (function(){
      return spp;
    });
    sbp.override = io;
    apply(sb, overrides);
    sb.extend = function(o){return extend(sb, o);};
    return sb;
  };
}();

//将Events属性继承给Dialog
Dialog = extend( Dialog, Events );

//为Dialog新增 method show,其内触发 event show
Dialog.prototype.show = function( txt ){
  this.emit( 'show', txt );
}

var dialog = new Dialog();

//添加监听事件show
dialog.on( 'show', function(txt){ console.log( txt )});

//执行method show时,就会触发其内定义的show events,输出 this is show
dialog.show( 'this is show' );

ログイン後にコピー
このようにして、コンポーネントにイベント メカニズムが実装され、メソッドが呼び出されるときにイベントがトリガーされます。

6. まとめ

Nodejs は優れた監視メカニズムを提供し、そのすべてのモジュールでも使用されます。たとえば、http サービスを開始するとき、その接続/終了を監視します。 http.request 監視データ・終了など 監視の仕組みを理解することはnodejsを学び理解する基礎となり、プログラミングのアイデア向上にも役立ちます。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート