国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

淺談Nodejs觀察者模式

2019-11-20 11:28:29
字體:
來源:轉載
供稿:網友

一、前言

Nodejs使用有些日子了,近來再回顧下其API、多使用新特性,以期有更高層次的掌握,本次API的總結區別于單純對英文版的漢化,會多做些擴展和自己的理解,希望對大家有所幫助,先從最核心的Events開始

Nodejs的Events實現了一種觀察者模式,其支持了Nodejs的核心機制,且http / fs / mongoose等都繼承了Events,可以添加監聽事件。這種設計模式在客戶端的組件編程思想里經常會用到,我們先簡單了解下該模式。

首次接觸 觀察者模式是在Extjs框架的 Ext.util.observable源碼,那時剛接觸js,感覺這種模式很強大,也是我最早接觸到的設計模式,后來在 underscore.js 源碼里也有看到,且后者實現更簡捷、優雅,我編寫組件時也基本是按照這種思想。

觀察者模式就是為某一對象添加一監聽事件,如on('show', callback),由該對象在符合條件如show時自行觸發,瀏覽器本身已經為dom實現了監聽機制。

如我們為input添加keyup監聽,目的是為了輸出其value

$( 'input' ).on( 'keyup', function(){   console.log( this.value );} );

這樣輸入內容時會自行在日志中輸出其value。

但我們自己做一個組件如Dialog,如何監聽最常用的show / hide事件呢?

初級的做法是實例化時直接將回調配置進去,如

var dialog = new Dialog({  content: '這里是彈出框的內容',  show: function(){    console.log( '當彈框時輸出此段內容' );  }});

這樣也可以用,不過顯然不夠靈活,如何將dialog做的像input那樣可隨時添加事件呢

二、觀察者模式實現

首先實現Events對象,這里提供基礎的監聽on和觸發emit,事件是以json形式壓棧在對象的_events里

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,
僅實現創建; method: show / hide; event: show / hide;

看效果時,加上這段樣式

.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 );

生成實例,并為其添加三個show及hide監聽事件

var dialog = window.dialog = new Dialog({  content: 'dialog one'});dialog.on( 'show', function( txt ){  console.log( 'dialog show one ' + txt );} );//do somethingdialog.on( 'show', function( txt ){  console.log( 'dialog show two ' + txt );} );//do somethingdialog.on( 'show', function( txt ){  console.log( 'dialog show three ' + txt );} );//do somethingdialog.on( 'hide', function( txt ){  console.log( 'dialog hide one ' + txt );} );//do somethingdialog.on( 'hide', function( txt ){  console.log( 'dialog hide two ' + txt );} );//do somethingdialog.on( 'hide', function( txt ){  console.log( 'dialog hide three ' + txt );} );

我們分六次添加了六個不同的show事件和hide事件。
當執行 dialog.show() 時就會輸出三條對應的日志。添加的事件保存在 dialog._events里,如圖

pic

添加的三個show都輸出成功,事件保存在_events屬性里

nodejs Events也是實現了這一過程。

三、結構

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 }*/

四、API

其提供的method有on,是addListener的簡寫都是為實例添加監聽事件,其它屬性也都顧名思義,就簡單說明下

property_events: undefined,   //以壓棧形式存放on進來的事件_maxListeners: undefined  //設置最大監聽數,超出提warn----------------------------------------------------------------------------------------------------------------methodsetMaxListeners: [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' )-----------------------------------------------------------------------------------------------還有兩個eventnewListener / 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 ); })

五、應用

使用Events,通常就直接實例化即可,如上面API部分所例

不過,如果我們在nodejs端也實現了一個組件,如前面的Dialog,如何讓Dialog也具備Events的功能呢?可以用Extjs實現的 extend方案

創建Dialog構建器

var Dialog = function(){  //do something}//抽象apply函數,提供屬性的深度復制,同上面的extendfunction 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 ? 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屬性繼承給DialogDialog = extend( Dialog, Events );//為Dialog新增 method show,其內觸發 event showDialog.prototype.show = function( txt ){  this.emit( 'show', txt );}var dialog = new Dialog();//添加監聽事件showdialog.on( 'show', function(txt){ console.log( txt )});//執行method show時,就會觸發其內定義的show events,輸出 this is showdialog.show( 'this is show' );

這樣就為一個組件實現了Events機制,當調用method時,會觸發event

六、總結

nodejs提供了很好的監聽機制,并且也應用在其所有模塊,其支持了nodejs最特色的I/O模式,如我們啟動http服務時會監聽其 connect / close,http.request時會監聽 data / end等,了解監聽機制對學習理解nodejs的基礎,也對提升編程思想有益。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 安康市| 简阳市| 桓仁| 河北区| 兰西县| 拜城县| 凤翔县| 鞍山市| 三亚市| 商都县| 新兴县| 勐海县| 堆龙德庆县| 中阳县| 贵溪市| 荣成市| 怀远县| 建平县| 彝良县| 文登市| 迁安市| 海丰县| 西乌| 瑞丽市| 濉溪县| 宜阳县| 海丰县| 阿瓦提县| 灵丘县| 平陆县| 正阳县| 永年县| 玉屏| 称多县| 镶黄旗| 西林县| 噶尔县| 太仓市| 西华县| 洛浦县| 依兰县|