nodeJS之eventproxy源码解读
1.源碼縮影
!(function (name, definition) { var hasDefine = typeof define === 'function', //檢查上下文環境是否為AMD或CMD hasExports = typeof module !== 'undefined' && module.exports; //檢查上下文環境是否為Node if (hasDefine) { define(definition); //AMD環境或CMD環境 } else if (hasExports) { module.exports = definition(require('debug')('eventproxy')); //構建為普通Node模塊 } else { this[name] = definition(); //構建在window.name中 } })('EventProxy', function (debug) { debug = debug || function () {}; //為debug設置默認值 var EventProxy = function () { //EventProxy構造函數 if (!(this instanceof EventProxy)) { //防止構造函數以call或apply方式被其它對象調用,只能new return new EventProxy(); } this._callbacks = {}; //new之后對象屬性_callbacks,保存要處理的回調函數 this._fired = {}; //new之后對象屬性_fired,保存回調之后的結果 }; EventProxy.prototype... //EventProxy的諸原型函數,所謂原型函數,就是這些函數為new之后對象多共享 EventProxy.create = function () {...}; //EventProxy的屬性create,指向普通函數 EventProxy.EventProxy = EventProxy; //EventProxy的屬性EventProxy指向自身 return EventProxy; //返回EventProxy構造函數 }); 源碼解讀: 上面大致展示了eventproxy的結構,首先它使用閉包的形式保證了代碼的整潔;其次為了適應不同的使用場合,代碼中都做了必要的處理,而我們使用最多的無疑是作為nodejs的模塊:檢查exports,如果存在,則構建為nodejs模塊:module.exports = definition(require(‘debug’)(‘eventproxy’));而definition則是function(debug)開始一直到文件結構的函數,其中debug作為調試,暫且不管,剩下的就是EventProxy函構造函數,EventProxy原型函數,EventProxy.create一般函數,最后返回EventProxy函構造函數.于是構建的結果相當于module.exports = EventProxy;所以在其它模塊中的require(“eventproxy”)指向的就是EventProxy構造函數.
2.原型函數addListener,別名bind,on,subscribe
EventProxy.prototype.addListener = function (ev, callback) { debug('Add listener for %s', ev); this._callbacks[ev] = this._callbacks[ev] || []; this._callbacks[ev].push(callback); return this; }; 源碼解讀: 該方法接收兩個參數:事件名稱和回調函數,首先在_callbacks對象上面開辟事件的數組,之后把回調函數放進該數組中.
3.原型函數headbind
EventProxy.prototype.headbind = function (ev, callback) { debug('Add listener for %s', ev); this._callbacks[ev] = this._callbacks[ev] || []; this._callbacks[ev].unshift(callback); return this; }; 源碼解讀: 該方法與addListene方法相同,只不過是把回調函數放在了數組的第一個
4.原型函數removeListener,別名unbind
EventProxy.prototype.removeListener = function (eventName, callback) { var calls = this._callbacks; if (!eventName) { debug('Remove all listeners'); this._callbacks = {}; } else { if (!callback) { debug('Remove all listeners of %s', eventName); calls[eventName] = []; } else { var list = calls[eventName]; if (list) { var l = list.length; for (var i = 0; i < l; i++) { if (callback === list[i]) { debug('Remove a listener of %s', eventName); list[i] = null; } } } } } return this; }; 源碼解讀: 該方法是為移除特定的回調函數:(1)兩個參數都不存在,移除所有回調函數(2)eventName存在,callback不存在,移除eventName上的所有函數(3)eventName存在,callback存在,移除eventName上的callback函數.
5.原型函數removeAllListeners
EventProxy.prototype.removeAllListeners = function (event) { return this.unbind(event); }; 源碼解讀: 該方法是為移除event上所有的函數.
6.原型函數bindForAll
EventProxy.prototype.bindForAll = function (callback) { this.bind(ALL_EVENT, callback); }; 源碼解讀: 該方法是為綁定全局回調函數 all為callback
7.原型函數unbindForAll
EventProxy.prototype.unbindForAll = function (callback) { this.unbind(ALL_EVENT, callback); }; 源碼解讀: 該方法是為移除全局回調函數all的callback函數
8.原型函數trigger,別名emit,fire
EventProxy.prototype.trigger = function (eventName, data) { var list, ev, callback, args, i, l; var both = 2; var calls = this._callbacks; debug('Emit event %s with data %j', eventName, data); while (both--) { //執行兩次,第一次執行eventName的回調函數,第二次執行全局__all__的回調函數 ev = both ? eventName : ALL_EVENT; list = calls[ev]; //回調函數列表 if (list) { for (i = 0, l = list.length; i < l; i++) { if (!(callback = list[i])) { //如果回調函數不存在,移除 list.splice(i, 1); i--; l--; } else { args = both ? SLICE.call(arguments, 1) : arguments; callback.apply(this, args); //非全局回調函數,值傳入data,全局傳入全部參數 } } } } return this; }; 源碼解讀: 該方法是為eventName事件觸發函數,或對eventName事件注值函數:(1)事件觸發會做兩件事情,一是觸發該事件的函數數組,把data出入一一執行,二是執行全局回調函數數組,把事件名稱和data傳進去,它內部會判斷是否所有要處理的事件都已處理完畢,處理完畢就執行后面真正的全局回調,如果沒有完成則會退出全局回調函數.
9.原型函數once
EventProxy.prototype.once = function (ev, callback) { var self = this; var wrapper = function () { callback.apply(self, arguments); //回調wrapper時回調源回調函數,再解綁 self.unbind(ev, wrapper); }; this.bind(ev, wrapper); //綁定的是wrapper,會回調wrapper return this; }; 源碼解讀: 該方法是為一次性綁定函數,即回調之后會移除,是最常用的綁定函數,它綁定的不是原有回調函數,而是進行了包裝,因為在包裝內部要做解綁處理;雖然進行了包裝,但是回調的時候傳入的參數還是在內部傳入遠回調函數執行,只是多了一步解綁.
10.臨時變量later
var later = typeof process !== 'undefined' && process.nextTick || function (fn) { setTimeout(fn, 0); }; 源碼解讀: 存在process.nextTick,later就等于process.nextTick,沒有就用setTimeout.
11.原型函數emitLater
EventProxy.prototype.emitLater = function () { var self = this; var args = arguments; later(function () { self.trigger.apply(self, args); }); }; 源碼解讀: 遲緩觸發,參數應為eventName,data.
12.原型函數immediate,別名asap
EventProxy.prototype.immediate = function (ev, callback, data) { this.bind(ev, callback); this.trigger(ev, data); return this; }; 源碼解讀: 即時的,綁定事件回調函數,觸發
13.臨時變量_assign
var _assign = function (eventname1, eventname2, cb, once) { var proxy = this; var argsLength = arguments.length; //參數個數 var times = 0; //已觸發注值個數 var flag = {}; //已觸發注值標志 // Check the arguments length. if (argsLength < 3) { //參數小于3,返回 return this; } var events = SLICE.call(arguments, 0, -2); //取得傳入的event數組 var callback = arguments[argsLength - 2]; //取得回調函數 var isOnce = arguments[argsLength - 1]; //取得是否一次調用標志 // Check the callback type. if (typeof callback !== "function") { //沒有回調函數,返回 return this; } debug('Assign listener for events %j, once is %s', events, !!isOnce); var bind = function (key) { //為處理回調函數 var method = isOnce ? "once" : "bind"; //根據標志取得調用綁到的方法 proxy[method](key, function (data) { //綁定事件和回調函數,回調函數為內建,回調的時候會傳入data參數 proxy._fired[key] = proxy._fired[key] || {}; //初始化結果保存位置 proxy._fired[key].data = data; //把數據注入_fired中 if (!flag[key]) { //沒有回調過,標志置為true,事件回調個數+1 flag[key
轉載于:https://www.cnblogs.com/zhishaofei/p/4319351.html
總結
以上是生活随笔為你收集整理的nodeJS之eventproxy源码解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 起个网名微信的女生
- 下一篇: 关于chrome等浏览器不支持showM