一, 前言
Node.JS 使用有些日子了, 近来再回顾下其 API, 多使用新特性, 以期有更高层次的掌握, 本次 API 的总结区别于单纯对英文版的汉化, 会多做些扩展和自己的理解, 希望对大家有所帮助, 先从最核心的 Events 开始
Node.JS 的 Events 实现了一种观察者模式, 其支持了 Node.JS 的核心机制, 且 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 那样可随时添加事件呢. 下面是一个极简的实现
- 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{
- 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 = $( '').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 );
- var dialog = Windows.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 );
- } );
- 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 }
- */
- 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( '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' ]
- */
- 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 );
- })
- // 抽象 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 == '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, 其内触发 event show
- Dialog.prototype.show = function( txt ){
- this.emit( 'show', txt );
- }
- var dialog = new Dialog();
- // 添加监听事件 show
- dialog.on( 'show', function(txt){ console.log( txt )});
- // 执行 method show 时, 就会触发其内定义的 show events, 输出 this is show
- dialog.show( 'this is show' );
来源: https://www.w3ctech.com/topic/1542