Home > Web Front-end > JS Tutorial > body text

Introduction to Nodejs observer pattern

不言
Release: 2018-06-30 16:11:12
Original
1376 people have browsed it

This article mainly introduces the relevant information about the Nodejs observer mode. Friends who need it can refer to it

1. Preface

Nodejs uses some days Recently, I will review its API and use more new features in order to have a higher level of mastery. This summary of the API is different from the simple Chinese version of the English version. I will do more expansion and my own understanding. I hope it can be helpful to everyone. To help, let’s start with the core Events

Nodejs’ Events implements an observer mode, which supports the core mechanism of Nodejs, and http/fs/mongoose, etc. all inherit Events and can add listeners event. This design pattern is often used in client-side component programming ideas. Let’s briefly understand this pattern first.

The first time I came into contact with the observer pattern was in the Ext.util.observable source code of the Extjs framework. I was new to js at that time and felt that this pattern was very powerful. It was also the first design pattern I came into contact with. Later, I used it in underscore.js It can also be seen in the source code, and the latter implementation is simpler and more elegant. I basically follow this idea when writing components.

The observer mode is to add a monitoring event to an object, such as on('show', callback), which is triggered by the object when it meets the conditions such as show. The browser itself has already implemented monitoring for the dom. mechanism.

If we add keyup monitoring for input, the purpose is to output its value

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

In this way, when inputting content, it will automatically output its value in the log value.

But when we make a component such as Dialog, how do we monitor the most commonly used show/hide events?

The basic approach is to directly configure the callback during instantiation, such as

var dialog = new Dialog({
  content: '这里是弹出框的内容',
  show: function(){
    console.log( '当弹框时输出此段内容' );
  }
});
Copy after login

This can also be used, but it is obviously not flexible enough. How can we make the dialog like input and can add events at any time?

2. Observation Implementation of the operator pattern

First implement the Events object, which provides basic monitoring on and triggering emit. Events are stacked in the _events of the object in the form of 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 );
      } )
    }
  }   
}
Copy after login

Abstract another function to copy attributes for objects

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 ];
    }
  }
}
Copy after login

Implement a Dialog,
Only create; method : show / hide; event: show / hide;

When looking at the effect, add this style

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

Implement the component

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

Extended attributes

extend( Dialog.prototype, {

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

  render: function( config ){
    this.el = $( &#39;<p>&#39; ).addClass( &#39;dialog&#39; );
    this.el.html( config.content );
    $( &#39;body&#39; ).append( this.el );
  },

  show: function( param ){
    this.el.fadeIn();
    this.emit( &#39;show&#39;, param );
  },

  hide: function( param ){
    this.el.fadeOut();
    this.emit( &#39;hide&#39;, param );
  }

}, Events );
Copy after login

Generate an instance and add three show and hide monitors to it Event

var dialog = window.dialog = new Dialog({
  content: &#39;dialog one&#39;
});

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

//do something

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

//do something

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

//do something

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

//do something

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

//do something

dialog.on( &#39;hide&#39;, function( txt ){
  console.log( &#39;dialog hide three &#39; + txt );
} );
Copy after login

We added six different show events and hide events in six times.
When dialog.show() is executed, three corresponding logs will be output. The added events are saved in dialog._events, as shown in the figure

Introduction to Nodejs observer pattern

The three added shows are all output successfully, and the events are saved in the _events attribute

nodejs Events also implements this process.

3. Structure

var Events = require( &#39;events&#39; );
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( &#39;show&#39;, function( txt ){ console.log( &#39;one &#39; + txt )})
myEmitter.on( &#39;show&#39;, function( txt ){ console.log( &#39;tow &#39; + txt )})
myEmitter.on( &#39;hide&#39;, function( txt ){ console.log( &#39;one &#39; + txt )})
myEmitter.emit( &#39;show&#39;, &#39;show&#39; );
myEmitter.setMaxListeners( 10 );
console.log( myEmitter );
/*
{ domain: null,
  _events: { show: [ [Function], [Function] ], hide: [Function] }, //添加后的事情,以json形式存放
  _maxListeners: 10 }
*/
Copy after login

##4. API

Its The provided methods include on, which is the abbreviation of addListener. They all add listening events to the instance. The other attributes are as their names suggest. Let’s briefly explain them

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( &#39;show&#39;, &#39;prompt content&#39; );
 参数1为事件名,参数二供on回调里的参数
 */

addListener: [Function: addListener],
 /*
添加监听事件
emitter.addListener( event, listener );
如 myEmitter.addListener( &#39;show&#39;, 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( &#39;show&#39;, function( txt ){ console.log( txt ) } );
当myEmitter.emit执行第二次时没有输出
 */

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

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

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

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

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

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

 emitter.on( &#39;removeListener&#39;, function(){
  console.log( emitter.listeners( &#39;show&#39; ) );
  console.log( arguments );
 })
Copy after login

5. Application

Using Events, usually just instantiate it directly, as shown in the API section above

However, if we also implement a component on the nodejs side, such as the previous Dialog, how to make the Dialog Does it also have the function of Events? You can use the extend solution implemented by Extjs

Create a Dialog builder

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 == &#39;object&#39;){
      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,其内触发 event show
Dialog.prototype.show = function( txt ){
  this.emit( &#39;show&#39;, txt );
}

var dialog = new Dialog();

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

//执行method show时,就会触发其内定义的show events,输出 this is show
dialog.show( &#39;this is show&#39; );
Copy after login

In this way, the Events mechanism is implemented for a component. When method is called , will trigger the event

6. Summary

nodejs provides a good monitoring mechanism and is also applied to all its modules. It supports the most distinctive I of nodejs. /O mode, for example, when we start the http service, we will monitor its connect/close, when http.request, we will monitor data/end, etc. Understanding the monitoring mechanism is the basis for learning and understanding nodejs, and is also beneficial to improving programming ideas.

The above is the entire content of this article. I hope it will be helpful to everyone's study. For more related content, please pay attention to the PHP Chinese website!

Related recommendations:

How to use Buffer to encode and decode binary data in Node.js

NodeJs basic syntax and Type introduction

The above is the detailed content of Introduction to Nodejs observer pattern. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template