最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Nodejs觀察者模式

 更新時(shí)間:2015年10月13日 08:58:58   投稿:hebedich  
這篇文章主要介紹了淺談Nodejs觀察者模式的相關(guān)資料,需要的朋友可以參考下

一、前言

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

Nodejs的Events實(shí)現(xiàn)了一種觀察者模式,其支持了Nodejs的核心機(jī)制,且http / fs / mongoose等都繼承了Events,可以添加監(jiān)聽(tīng)事件。這種設(shè)計(jì)模式在客戶端的組件編程思想里經(jīng)常會(huì)用到,我們先簡(jiǎn)單了解下該模式。

首次接觸 觀察者模式是在Extjs框架的 Ext.util.observable源碼,那時(shí)剛接觸js,感覺(jué)這種模式很強(qiáng)大,也是我最早接觸到的設(shè)計(jì)模式,后來(lái)在 underscore.js 源碼里也有看到,且后者實(shí)現(xiàn)更簡(jiǎn)捷、優(yōu)雅,我編寫組件時(shí)也基本是按照這種思想。

觀察者模式就是為某一對(duì)象添加一監(jiān)聽(tīng)事件,如on('show', callback),由該對(duì)象在符合條件如show時(shí)自行觸發(fā),瀏覽器本身已經(jīng)為dom實(shí)現(xiàn)了監(jiān)聽(tīng)機(jī)制。

如我們?yōu)閕nput添加keyup監(jiān)聽(tīng),目的是為了輸出其value

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

這樣輸入內(nèi)容時(shí)會(huì)自行在日志中輸出其value。

但我們自己做一個(gè)組件如Dialog,如何監(jiān)聽(tīng)最常用的show / hide事件呢?

初級(jí)的做法是實(shí)例化時(shí)直接將回調(diào)配置進(jìn)去,如

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

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

二、觀察者模式實(shí)現(xiàn)

首先實(shí)現(xiàn)Events對(duì)象,這里提供基礎(chǔ)的監(jiān)聽(tīng)on和觸發(fā)emit,事件是以json形式壓棧在對(duì)象的_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 );
      } )
    }
  }   
}

再抽象一個(gè)函數(shù)用于為對(duì)象復(fù)制屬性

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 ];
    }
  }
}

實(shí)現(xiàn)一個(gè)Dialog,
僅實(shí)現(xiàn)創(chuàng)建; method: show / hide; event: show / hide;

看效果時(shí),加上這段樣式

.dialog{
  position: fixed;
  top: 50%;
  left: 50%;
  margin: -50px 0 0 -100px;
  width: 200px;
  height: 120px;
  background: #fff;
  border: 5px solid #afafaf;
}

實(shí)現(xiàn)組件

var Dialog = function( config ){
  this.config = config;
  this.init( this.config );
};

擴(kuò)展屬性

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

生成實(shí)例,并為其添加三個(gè)show及hide監(jiān)聽(tīng)事件

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

我們分六次添加了六個(gè)不同的show事件和hide事件。
當(dāng)執(zhí)行 dialog.show() 時(shí)就會(huì)輸出三條對(duì)應(yīng)的日志。添加的事件保存在 dialog._events里,如圖

pic

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

nodejs Events也是實(shí)現(xiàn)了這一過(guò)程。

三、結(jié)構(gòu)

var Events = require( 'events' );
console.log( Events );
/*
輸出如下數(shù)據(jù),可以看出 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: {},   //可以看到實(shí)例本身也有_events屬性,添加的監(jiān)聽(tīng)的事件就保存在這里
  _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的簡(jiǎn)寫都是為實(shí)例添加監(jiān)聽(tīng)事件,其它屬性也都顧名思義,就簡(jiǎn)單說(shuō)明下

property
_events: undefined,   //以壓棧形式存放on進(jìn)來(lái)的事件
_maxListeners: undefined  //設(shè)置最大監(jiān)聽(tīng)數(shù),超出提warn

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

method
setMaxListeners: [Function: setMaxListeners], 
/*設(shè)置私有屬性_maxListeners的值,默認(rèn)Events會(huì)在當(dāng)某監(jiān)聽(tīng)事件多于10個(gè)時(shí)發(fā)現(xiàn)警告(見(jiàn)上面Events.defaultMaxListeners),以防止內(nèi)存泄露,如
(node) warning: possible EventEmitter memory leak detected. 11 show listeners added. Use emitter.setMaxListeners() to increase limit.
但這只是個(gè)友好的提醒,可以通過(guò)設(shè)置最大監(jiān)聽(tīng)數(shù)來(lái)規(guī)避這個(gè)問(wèn)題
myEmitter.setMaxListeners( 20 );
*/

emit: [Function: emit],
 /*觸發(fā)監(jiān)聽(tīng)事件
emitter.emit( event, [arg1], [arg2], ... )
如myEmitter.on( 'show', 'prompt content' );
 參數(shù)1為事件名,參數(shù)二供on回調(diào)里的參數(shù)
 */

addListener: [Function: addListener],
 /*
添加監(jiān)聽(tīng)事件
emitter.addListener( event, listener );
如 myEmitter.addListener( 'show', function( txt ){ console.log( txt ) } );
參數(shù)一是事件名,參數(shù)二是對(duì)應(yīng)的回調(diào),回調(diào)里的參數(shù)就是 emit里的arguments.prototype.slice.call(1);
 */

on: [Function: addListener],
 /*
是addListener簡(jiǎn)寫
 */

once: [Function: once],
 /*
作用同 on,不過(guò)emit一次后就失效了
emitter.once( event, listener );
如 myEmitter.once( 'show', function( txt ){ console.log( txt ) } );
當(dāng)myEmitter.emit執(zhí)行第二次時(shí)沒(méi)有輸出
 */

removeListener: [Function: removeListener],
 /*
移除指定事件的指定回調(diào),此時(shí)回調(diào)不能再用匿名函數(shù)。
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],
 /*
 刪除指定事件的所有回調(diào)
 emitter.removeAllListeners( [ event ] );
 如 
  myEmitter.removeAllListeners( 'show' );   //刪除所有show監(jiān)聽(tīng)
  myEmitter.removeAllListeners();   //刪除所有監(jiān)聽(tīng)
 */

listeners: [Function: listeners]
/*
查看指定監(jiān)聽(tīng)
emitter.listeners( event );
如 myEmitter.listeners( 'show' ); //返回一個(gè)數(shù)組
同我們前面使用的 myEmitter._events[ 'show' ]
*/

另外Events類本身提供了一個(gè)方法
Events.listenerCount( emitter, event ); 獲取指定實(shí)例下指定監(jiān)聽(tīng)數(shù)
如 Event.listenerCount( myEmitter, 'show' )

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

還有兩個(gè)event
newListener / remoteListener,分別應(yīng)用于為實(shí)例添加( on / once )和刪除( removeListener ) 操作。
emitter.on( event, listener );
emitter.on( 'newListener', function( event, listener ){
  console.log( emitter.listeners( 'show' ) );   //注意,此時(shí)監(jiān)聽(tīng)還并沒(méi)有添加到 emitter.listeners
  console.log( arguments );  
 });

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

五、應(yīng)用

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

不過(guò),如果我們?cè)趎odejs端也實(shí)現(xiàn)了一個(gè)組件,如前面的Dialog,如何讓Dialog也具備Events的功能呢?可以用Extjs實(shí)現(xiàn)的 extend方案

創(chuàng)建Dialog構(gòu)建器

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

//抽象apply函數(shù),提供屬性的深度復(fù)制,同上面的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函數(shù),用于實(shí)現(xiàn)繼承
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屬性繼承給Dialog
Dialog = extend( Dialog, Events );

//為Dialog新增 method show,其內(nèi)觸發(fā) event show
Dialog.prototype.show = function( txt ){
  this.emit( 'show', txt );
}

var dialog = new Dialog();

//添加監(jiān)聽(tīng)事件show
dialog.on( 'show', function(txt){ console.log( txt )});

//執(zhí)行method show時(shí),就會(huì)觸發(fā)其內(nèi)定義的show events,輸出 this is show
dialog.show( 'this is show' );

這樣就為一個(gè)組件實(shí)現(xiàn)了Events機(jī)制,當(dāng)調(diào)用method時(shí),會(huì)觸發(fā)event

六、總結(jié)

nodejs提供了很好的監(jiān)聽(tīng)機(jī)制,并且也應(yīng)用在其所有模塊,其支持了nodejs最特色的I/O模式,如我們啟動(dòng)http服務(wù)時(shí)會(huì)監(jiān)聽(tīng)其 connect / close,http.request時(shí)會(huì)監(jiān)聽(tīng) data / end等,了解監(jiān)聽(tīng)機(jī)制對(duì)學(xué)習(xí)理解nodejs的基礎(chǔ),也對(duì)提升編程思想有益。

相關(guān)文章

  • nodejs實(shí)現(xiàn)一個(gè)word文檔解析器思路詳解

    nodejs實(shí)現(xiàn)一個(gè)word文檔解析器思路詳解

    這篇文章主要介紹了nodejs實(shí)現(xiàn)一個(gè)word文檔解析器的思路詳解,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-08-08
  • 手把手教你把nodejs部署到linux上跑出hello world

    手把手教你把nodejs部署到linux上跑出hello world

    本篇文章主要介紹了手把手教你把nodejs部署到linux上跑出hello world,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-06-06
  • 淺談Node.js:Buffer模塊

    淺談Node.js:Buffer模塊

    本篇文章主要介紹了Node.js:Buffer模塊,詳細(xì)的介紹了創(chuàng)建Buffer實(shí)例,具有一定的參考價(jià)值,有需要的可以了解一下。
    2016-12-12
  • Node.js處理多個(gè)請(qǐng)求的技巧和方法

    Node.js處理多個(gè)請(qǐng)求的技巧和方法

    Node.js在處理多個(gè)請(qǐng)求方面具有優(yōu)勢(shì),它利用事件驅(qū)動(dòng)和非阻塞式I/O的特性,能夠高效地處理并發(fā)請(qǐng)求,提供快速響應(yīng)和良好的可擴(kuò)展性,這篇文章主要介紹了Node.js如何處理多個(gè)請(qǐng)求,需要的朋友可以參考下
    2023-11-11
  • nodejs讀寫json文件的簡(jiǎn)單方法(必看)

    nodejs讀寫json文件的簡(jiǎn)單方法(必看)

    下面小編就為大家?guī)?lái)一篇nodejs讀寫json文件的簡(jiǎn)單方法(必看)。
    2017-03-03
  • node如何實(shí)現(xiàn)簡(jiǎn)單的腳手架淺析

    node如何實(shí)現(xiàn)簡(jiǎn)單的腳手架淺析

    在工作中,需要開(kāi)發(fā)一個(gè)腳手架,用于給相關(guān)用戶提供相關(guān)的開(kāi)發(fā)便利性,下面這篇文章主要給大家介紹了關(guān)于node如何實(shí)現(xiàn)簡(jiǎn)單的腳手架的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • 基于nodejs+express(4.x+)實(shí)現(xiàn)文件上傳功能

    基于nodejs+express(4.x+)實(shí)現(xiàn)文件上傳功能

    通過(guò)一段時(shí)間的查閱資料發(fā)現(xiàn)實(shí)現(xiàn)上傳的方式有:1.express中間件multer模塊2.connect-multiparty模塊(但現(xiàn)在 官方不推薦 )3.使用multiparty模塊實(shí)現(xiàn)4.使用formidable插件實(shí)現(xiàn),本文給大家介紹nodejs+express(4.x+)實(shí)現(xiàn)文件上傳功能,需要的朋友參考下
    2015-11-11
  • Node.js中的npm單獨(dú)與批量升級(jí)依賴包的方式超詳細(xì)講解

    Node.js中的npm單獨(dú)與批量升級(jí)依賴包的方式超詳細(xì)講解

    npm outdated僅檢查所有已安裝包的依賴關(guān)系,并將當(dāng)前版本遠(yuǎn)程倉(cāng)庫(kù)中的最新版本進(jìn)行對(duì)比,不會(huì)升級(jí),這篇文章主要介紹了Node.js中的npm單獨(dú)與批量升級(jí)依賴包的方式超詳細(xì)講解,需要的朋友可以參考下
    2024-02-02
  • Node.js使用定時(shí)器的三種方法

    Node.js使用定時(shí)器的三種方法

    在Node.js中使用定時(shí)器是一項(xiàng)常見(jiàn)且重要的任務(wù),本文主要介紹了Node.js使用定時(shí)器的三種方法,包括setTimeout、setInterval和setImmediate等方法,感興趣的可以了解一下
    2024-02-02
  • Windows部署NVM并下載多版本Node.js的方法(含刪除原有Node的方法)

    Windows部署NVM并下載多版本Node.js的方法(含刪除原有Node的方法)

    這篇文章主要介紹了Windows部署NVM并下載多版本Node.js的方法(含刪除原有Node的方法),文中通過(guò)圖文結(jié)合的方式講解的非常詳細(xì),對(duì)大家了解Node.js有一定的幫助,需要的朋友可以參考下
    2025-01-01

最新評(píng)論

石景山区| 林西县| 湖州市| 延寿县| 怀安县| 枣阳市| 比如县| 宜春市| 海南省| 宜兰市| 安乡县| 封丘县| 恩平市| 冷水江市| 灵台县| 周宁县| 休宁县| 电白县| 容城县| 闻喜县| 兴仁县| 四会市| 临沧市| 宝兴县| 沁水县| 绥中县| 都匀市| 荣昌县| 墨竹工卡县| 阿合奇县| 安达市| 阿瓦提县| 建湖县| 乃东县| 新昌县| 天祝| 木里| 阳山县| 洛隆县| 德兴市| 时尚|