On the _node.js of Nodejs Observer model

Source: Internet
Author: User
Tags emit extend

First, the preface

Nodejs used some days, recently reviewed its API, the use of new features, in order to have a higher level of mastery, the summary of the API is different from the simple English version of the Chinese, will do more to expand and their own understanding, hoping to help everyone, first from the core of events began

Nodejs's events implement an observer pattern that supports the core mechanism of Nodejs, and Http/fs/mongoose and so on have inherited events and can add listening events. This design pattern is often used in the client's component programming thinking, and we'll take a quick look at the pattern.

First Contact observer mode is in the ExtJS framework of the Ext.util.observable source code, at that time just contact JS, feeling this mode is very powerful, but also my first contact with the design pattern, and later in the Underscore.js source code also saw, and the latter to achieve more simple, elegant, I also basically follow this idea when I write components.

The Observer pattern is to add a listener event to an object, such as on (' Show ', callback), which is triggered by the object when it meets the criteria such as show, and the browser itself has a listener mechanism for the DOM.

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

$ (' input '). On (' KeyUp ', function () {
   console.log (this.value);
});

This allows you to output its value in the log when you enter the content.

But we do a component like dialog, how to monitor the most commonly used show/hide events?

The primary approach is to configure the callback directly when instantiating, as

var dialog = New dialog ({
  content: ' Here is the contents of the pop-up box ',
  show:function () {
    console.log (' Output This section when the frame is ");
  }
);

This can also be used, but obviously not flexible enough, how to do dialog like input can add events at any time?

II. implementation of the Observer model

The events object is implemented first, where the underlying listening on and triggering emit is provided, and the event is pressed in JSON form in the _events of the object

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

Again abstract a function to copy attributes for an object

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

To achieve a dialog,
Implement creation only; Method:show/hide; Event:show/hide;

When you look 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;
}

Implementing components

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

Extended Properties

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

Generate an instance and add three show and hide listener events

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

We have added six different show events and hide events six times.
Three corresponding logs are output when the dialog.show () is executed. Added events saved in Dialog._events, as shown in

The three show that was added was exported successfully and the event was saved in the _events property

Nodejs events also achieved this process.

Third, the structure

var Events = require (' events ');
Console.log (Events); /* Output The following data, you can see events point to its eventemiter {[function:eventemitter] eventemitter: [circular], usingdomains: [Getter/setter]
, Defaultmaxlisteners:10, init: [function], listenercount: [function]} */var myemitter = new Events ();
Console.log (Myemitter); /* {domain:null, _events: {},//You can see that the instance itself also has the _events property, the added listening event is saved here _maxlisteners:undefined} * * * Console.log (Myem
ITTER.__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: [Functio N:listeners]} */Myemitter.on (' Show ', function (TXT) {console.log (' one ' + txt)}) Myemitter.on (' Show ', function (t XT) {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]},///Add things to JSON form _maxlisteners:

 10} */

IV. API

Its provided method has on, is addlistener the shorthand is to add the listener event for the instance, other attributes are also as the name suggests, simply explains the

Property _events:undefined,//In the form of a press stack to store on the event _maxlisteners:undefined//Set the maximum number of listeners, exceeding the Warn---------------------------- ------------------------------------------------------------------------------------method Setmaxlisteners: [ Function:setmaxlisteners],/* Sets the value of the private property _maxlisteners, and the default events will find a warning when there are more than 10 listeners (see above Events.defaultmaxlisteners) To prevent memory leaks, such as (node) warning:possible Eventemitter memory leak detected. One show listeners added.
Use Emitter.setmaxlisteners () to increase limit.
But this is a friendly reminder that you can circumvent this problem by setting the maximum number of listeners myemitter.setmaxlisteners (20); * * Emit: [Function:emit],/* Triggering listener Event Emitter.emit (event, [Arg1], [arg2], ...) such as Myemitter.on (' show ', ' Prompt content ')
 ;
Parameter 1 is the event name, and the parameter is two for the parameter in the callback. * AddListener: [Function:addlistener],/* Add listener Event Emitter.addlistener (event, listener);
such as Myemitter.addlistener (' Show ', function (TXT) {console.log (TXT)});
 The parameter is the event name, the parameter two is the corresponding callback, the parameter in the callback is the Arguments.prototype.slice.call (1) in the emit. */on: [Function:addlistener],/* is addListener shorthand * * once: [FuNction:once],/* function with on, but emit once after the failure of the Emitter.once (event, listener);
such as Myemitter.once (' Show ', function (TXT) {console.log (TXT)});
When Myemitter.emit executes the second time there is no output/removelistener: [Function:removelistener],/* Removes the specified callback for the specified event, at which point the callback cannot use the anonymous function.
Emitter.removelistener (event, listener);
such as 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],/* Delete all callback emitter.removealllisteners for the specified event ([Event]);   such as Myemitter.removealllisteners (' Show ');   Remove all show listening myemitter.removealllisteners ();
Delete all listening/listeners: [Function:listeners]/* View designated Listening emitter.listeners (event); such as Myemitter.listeners (' Show '); Returns an array with the myemitter._events[' show '] we used earlier, and the events class itself provides a method of Events.listenercount (emitter, event); Gets the specified number of listeners under the specified instance, such as Event.listenercount (Myemitter, ' show '-----------------------------------------------------------------------------------------------
There are also two event Newlistener/remotelistener, which are used to add (on/once) and delete (RemoveListener) operations for instances respectively.
Emitter.on (event, listener);   Emitter.on (' Newlistener ', function (event, listener) {Console.log (Emitter.listeners (' Show '));  
 Note that the listener is not added to the emitter.listeners console.log (arguments) at this time;

 });
  Emitter.on (' RemoveListener ', function () {Console.log (Emitter.listeners (' Show '));
 Console.log (arguments);

 })

V. Application

Using events, you typically instantiate directly, as in the API section above

However, if we also implement a component on the Nodejs side, such as the previous dialog, how to let dialog also have events function? A extend scheme that can be implemented with ExtJS

Creating the Dialog Builder

var Dialog = function () {//do something}//abstract apply function that provides a deep copy of the attribute, with the above extend function apply (source) {var args = Arra
  Y.prototype.slice.call (arguments, 1);
    for (var i = 0, parent; parent = args[i]; i++) {for (Var prop in parent) {source[prop] = parent[prop]; 
      }}//abstract extend function, used to implement inherit 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;
};

}();

The events attribute is inherited to Dialog Dialog = Extend (Dialog, events);

Add method for Dialog, which triggers event show Dialog.prototype.show = function (txt) {this.emit (' show ', TXT);}

var dialog = New dialog ();

Add Listener Event Show Dialog.on (' Show ', function (TXT) {console.log (TXT)});

 When you execute method show, the show events that are defined are triggered, and the output is show dialog.show.

This implements the events mechanism for a component that triggers the event when method is invoked

Vi. Summary

Nodejs provides a good listening mechanism and is also applied to all of its modules, which support the Nodejs I/O mode, such as listening to the connect/close,http.request when we start the HTTP service. Understanding the listening mechanism is the basis for learning to understand Nodejs, and also beneficial to the promotion of programming ideas.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.