Maison >interface Web >js tutoriel >Introduction au modèle d'observateur Nodejs

Introduction au modèle d'observateur Nodejs

不言
不言original
2018-06-30 16:11:121407parcourir

Cet article présente principalement les informations pertinentes sur le mode observateur de Nodejs. Les amis qui en ont besoin peuvent s'y référer

1 Préface

Nodejs a été utilisé pour certains. Temps Récemment, je vais revoir son API et utiliser davantage de nouvelles fonctionnalités afin d'avoir un niveau de maîtrise plus élevé. Ce résumé de l'API est différent de la version chinoise simple de la version anglaise. Je ferai plus d'expansion et ma propre compréhension. J'espère que cela pourra être utile à tout le monde. Pour vous aider, commençons par les événements de base

Les événements de Nodejs implémentent un mode observateur, qui prend en charge le mécanisme de base de Nodejs, et http / fs / mongoose, etc. hérite des événements et peut ajouter un événement d'écoute. Ce modèle de conception est souvent utilisé dans les idées de programmation de composants côté client. Commençons par comprendre brièvement ce modèle.

La première fois que je suis entré en contact avec le modèle d'observateur, c'était dans le code source Ext.util.observable du framework Extjs à cette époque et je sentais que ce modèle était très puissant. C'est aussi le premier modèle de conception avec lequel je suis entré en contact. Plus tard, je l'ai utilisé dans underscore.js. Cela peut également être vu dans le code source, et cette dernière implémentation est plus simple et plus élégante. Je suis essentiellement cette idée lors de l'écriture des composants.

Le mode observateur consiste à ajouter un événement de surveillance à un objet, tel que on('show', callback), qui est déclenché par l'objet lorsqu'il remplit les conditions telles que show Le navigateur lui-même l'a déjà fait. mis en œuvre une surveillance pour le mécanisme dom.

Si nous ajoutons une surveillance des touches pour l'entrée, le but est de sortir sa valeur

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

De cette façon, lorsque le contenu d'entrée sera être automatiquement enregistré dans le journal Sortie de sa valeur.

Mais lorsque nous créons un composant tel que Dialog, comment pouvons-nous surveiller les événements d'affichage/masquage les plus couramment utilisés ?

L'approche de base consiste à configurer directement le rappel lors de l'instanciation, comme

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

Cela peut également être utilisé, mais ce n'est évidemment pas assez flexible. Comment faire en sorte que la boîte de dialogue ressemble à une entrée et puisse ajouter des événements à tout moment ?

2, Implémentation du modèle d'observateur

Implantez d'abord l'objet Events, qui fournit une surveillance de base et le déclenchement de l'émission. Les événements sont empilés dans les _events de l'objet sous la forme de. 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 );
      } )
    }
  }   
}

Une autre fonction abstraite est utilisée pour copier les attributs des objets

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

Implémenter un dialogue,
Créer uniquement ; méthode : afficher/masquer ; événement : afficher/masquer

Lorsque vous regardez l'effet, ajoutez ce style

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

Composant d'implémentation

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

Attributs étendus

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

Générer une instance et ajouté trois événements d'écoute afficher et masquer

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

Nous avons ajouté six événements d'affichage différents et masqué les événements six fois .
Lorsque dialog.show() est exécuté, trois journaux correspondants seront générés. Les événements ajoutés sont enregistrés dans dialog._events, comme indiqué dans la figure

Introduction au modèle dobservateur Nodejs

Les trois émissions ajoutées sont toutes sorties avec succès et les événements sont enregistrés dans l'attribut _events

nodejs Events implémente également ce processus.

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

4. >Les méthodes qu'il fournit incluent on, qui est l'abréviation de addListener. Elles ajoutent toutes des événements d'écoute à l'instance. Les autres attributs sont comme leur nom l'indique

<.>

5. Application
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 );
 })

À l'aide d'événements, il suffit généralement de l'instancier directement, comme indiqué dans la section API ci-dessus

Cependant, si nous implémentons également un composant sur nodejs côté, comme le précédent Dialog , comment faire en sorte que Dialog ait également la fonction d'événements ? Vous pouvez utiliser la solution d'extension implémentée par Extjs

pour créer un générateur de dialogue

De cette manière, le mécanisme d'événements est implémenté pour un composant. Lors de l'appel d'une méthode, l'événement
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; );

sera déclenché 6. Résumé

nodejs fournit un bon mécanisme de surveillance et est également appliqué à tous ses modules, qui prend en charge les fonctionnalités les plus uniques du mode E/S de nodejs, par exemple, lorsque nous démarrons le service http, nous surveillerons sa connexion/fermeture, lorsque http.request, nous surveillerons les données/fin, etc. Comprendre le mécanisme de surveillance est la base pour apprendre et comprendre nodejs, et est également bénéfique pour améliorer les idées de programmation. Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Comment utiliser Buffer pour encoder et décoder des données binaires dans Node.js

Syntaxe de base de NodeJs et Introduction des types


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn