Last active
December 17, 2018 09:25
-
-
Save movii/b0ae3a0cd1768b8b403a57fa044d46c0 to your computer and use it in GitHub Desktop.
第八章「发布—订阅模式」最后章节中的例子,包含离线消息接受和 namespace 实现的全局 Event 对象,原文中大段大段的代码没有注释(我看的是 kindle 的电子版,不知纸质的咋样),所以给加了一遍注释,还删掉些完全没有用到过但声明了的变量。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Event = (function() { | |
var Event; | |
var _default = 'default'; | |
Event = function() { | |
var _listen; | |
var _trigger; | |
var _remove; | |
var _shift = Array.prototype.shift; | |
var _unshift = Array.prototype.unshift; | |
var namespaceCache = {}; | |
var _create; | |
var each; | |
// @ary 传入的一个数组对象 array | |
// @fn 传入回调函数 | |
each = function(ary, fn) { | |
var ret; | |
for (var i = 0, l = ary.length; i < l; i++) { | |
var n = ary[i]; | |
ret = fn.call(n, i, n); | |
} | |
return ret; | |
}; | |
// @key => eventName | |
// @fn => 回调函数 | |
// @cache => 存储所有的 Event 的对象 | |
_listen = function(key, fn, cache) { | |
if (!cache[key]) { | |
cache[key] = []; | |
} | |
cache[key].push(fn); | |
}; | |
// @key => 同上 | |
// @cache => 同上 | |
// @fn => 同上 | |
_remove = function(key, cache, fn) { | |
if (cache[key]) { | |
if (fn) { | |
for (var i = cache[key].length; i >= 0; i--) { | |
if (cache[key] === fn) { | |
cache[key].splice(i, 1); | |
} | |
} | |
} else { | |
cache[key] = []; | |
} | |
} | |
}; | |
_trigger = function() { | |
// _create() 方法暴露的 _trigger() 方法, | |
// 接受的参数第一个是 cache 对象, | |
// 即保存所有 events 对象,利用 Array.prototype.shift() 进行弹出, | |
// 保存到当前 scope 的变量里 | |
var cache = _shift.call(arguments); | |
// key 即是需要触发的 eventName | |
var key = _shift.call(arguments); | |
// 在将保存 event 信息的对象,和作为 key 的 eventName 的参数弹出后, | |
// 传入函数的具体参数,数组对象 | |
var args = arguments; | |
// 保存一个指向 Event 对象的 ref | |
var _self = this; | |
// 取出 key 对应保存下来的所有回调函数 | |
stack = cache[key]; | |
// 当前 key 没有任何对应需要触发的方法时,终止当前函数继续执行 | |
if (!stack || !stack.length) { | |
return; | |
} | |
// 调用 each() 方法,将 key 所对应的函数以此执行 | |
return each(stack, function() { | |
// 这里的 this 指向传入的 callback 函数 | |
return this.apply(_self, args); | |
}); | |
}; | |
_create = function(namespace) { | |
// 保存命名空间的对象,_default => 'default' | |
var namespace = namespace || _default; | |
// 保存所有 eventName,fn 键值对的对象 | |
var cache = {}; | |
// 离线事件 | |
var offlineStack = []; | |
ret = { | |
// 调用 _listen() 方法,监听 key 所对应的事件 | |
listen: function(key, fn, last) { | |
_listen(key, fn, cache); | |
// 如果没有离线列队,终止继续执行; | |
// 如果有离线列队,则取出来以此调用执行。 | |
if (offlineStack === null) { | |
return; | |
} | |
// 判断 listen() 方法传入的参数有没有 'last', | |
// 见之后的 one() 方法; | |
// 如果有,将当前离线列队中的最后一个回调函数弹出并且执行 | |
// 如果没有,调用 each() 方法,依次执行回调函数 | |
if (last === 'last') { | |
offlineStack.length && offlineStack.pop()(); | |
} else { | |
each(offlineStack, function() { | |
this(); | |
}); | |
} | |
// 清空离线缓存列表 | |
offlineStack = null; | |
}, | |
// one() 方法,去除 cache 列队中的所有已存的回调函函数 cache = []; | |
// 如果当前离线列队中有没有触发的事件回调, | |
// 则取出列队中的最后一个执行,并且清空离线列队。 | |
one: function(key, fn, last) { | |
_remove(key, cache); | |
this.listen(key, fn, last); | |
}, | |
// 调用 _remove() 方法,取消已经订阅的事件方法 | |
remove: function(key, fn) { | |
_remove(key, cache, fn); | |
}, | |
trigger: function() { | |
var fn; | |
var args; | |
var _self = this; | |
// 见 _trigger() 方法, | |
// 这里将 cache (保存下来的所有 event) | |
// 和 trigger() 方法接收到的所有参数 arguments 数组对象, | |
// 打成一个新的数组,作为参数传给 _trigger() 函数并且执行。 | |
_unshift.call(arguments, cache); | |
args = arguments; | |
fn = function() { | |
return _trigger.apply(_self, args); | |
}; | |
// 如果当前 namespace 下在调用 trigger() 前没有调用 listen() , | |
// 那么离线列队 offliceStack = [],为一个空的数组, | |
// 就把当前 eventName 打进离线列队, | |
// 等到有了 listen() 的对象之后,再触发。 | |
if (offlineStack) { | |
return offlineStack.push(fn); | |
} | |
return fn(); | |
} | |
}; | |
// 判断 namespace 是否已经存在, | |
// 从而选择返回已经已经存在的对象,还是新的对象 | |
/* return namespace 语句等同于以下 if 从句 | |
if (namespace) { | |
if (namespaceCache[namespace]) { | |
return namespaceCache[namespace] | |
} else { | |
return namespaceCache[namespace] = ret; | |
} | |
} else { | |
return ret; | |
} | |
*/ | |
return namespace ? | |
(namespaceCache[namespace] ? | |
namespaceCache[namespace] : namespaceCache[namespace] = ret) : ret; | |
}; | |
return { | |
create: _create, | |
one: function(key, fn, last) { | |
var event = this.create(); | |
event.one(key, fn, last); | |
}, | |
remove: function(key, fn) { | |
var event = this.create(); | |
event.remove(key, fn); | |
}, | |
listen: function(key, fn, last) { | |
var event = this.create(); | |
event.listen(key, fn, last); | |
}, | |
trigger: function() { | |
var event = this.create(); | |
event.trigger.apply(this, arguments); | |
} | |
}; | |
}(); | |
return Event; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
最近也看到这里,那一坨代码看得我很疑惑,上网一搜,原来早有人有相同的感想了哈哈