这是我参与8月更文挑战的第13天,活动详情查看: 8月更文挑战”
前言
JavaScript异步编程 第二章 分布式事件
PubSub模式(发布、订阅)
实践中如何处理事件,直接给每一个事件添加一个处理器。那一个事件多个处理结果,那就会导致处理器的规模急剧膨胀。(可以理解为一个事见通过一个函数去实现,那么这个函数就要调用特别多的方法,这个函数就会有特别多行,难以维护。这一节也就是讨论通过PubSub模式去实现事件。)
接下来介绍Node的EventEmitter对象、Backbone的事件化模型、jQuery的自定义事件
浏览器允许向DOM元素附加事件处理器,形如link.onclick = clickHandler
如果想向一个元素附加两个点击事件处理器,则必须自行用一个封装函数汇集这两个处理器。
link.onclick = function() {
clickHandler1.apply(this, arguments)
clickHandler2.apply(this, arguments)
}
复制代码
W3C于2000年向DOM规范中添加了addEventListener
方法,而jQuery将其抽象成bind方法。
$(link)
.bind('click', clickHandler1) .bind('click', clickHandler2)
$( "button" ).on( "click", notify );
$( "button" ).on( "click", notify );
复制代码
jQuery将link元素的事件发布给了任何想订阅此事件的人。
而在Nodejs中,有实现了发布订阅模式的实体,这个实体是EventEmitter(事件发生器),其他对象可以继承它。且Nodejs中几乎所有的I/O源都是EventEmitter对象:文件流、HTTP服务器,甚至是应用进程本身。参考一个EventEmitter实例。
['room','moon','cow jumping over the moon']
.forEach(function(name){
process.on('exit',function(){
console.log('GoodNight, ' + name)
})
})
// 当exit事件发生时,发布给他人,执行匿名函数 打印信息
复制代码
(这个例子蛮水的)
EventEmitter对象
Node中的EventEmitter对象
1. 通过on方法给EventEmitter对象添加一个事件处理器
2. 通过emit方法调用给定事件类型的所有处理器
此处的事件与队列中的事件没有任何关系,nodejs约定,只能从EventEmitter对象的‘内部’触发事件。
实现PubSub
PubSub = {handlers: {}}
PubSub.on = function(eventType,handler){
if(!(eventType in this.handlers)){
this.handlers[eventType] = []
}
this.handlers[eventType].push(handler)
return this
}
PubSub.emit = function(eventType){
var handlerArgs = Array.prototype.slice.call(arguments, l);
for(var i=0;i<this.handlers[eventType].length;i++){
this.handlers[eventType][i].apply(this,handlerArgs)
}
return this
}
复制代码
同步性
JS中,事件触发同步执行处理器,处理器过多会导致相应迟钝。这里本书给出了一个简单解决方法,在之后的第四章会给出更复杂精妙的作业排队技术。
var tasks = []
setInterval(function(){
var nextTask
if(nextTask = tasks.shift()){
nextTask()
}
}, 0)
// 这个函数就不会一次同步执行所有的处理器
// 而是通过setInterval,异步执行各个处理器,不会阻塞到其他操作。
// 大概是这么回事,更细节精妙的参考第四章
复制代码
事件化模型
只要对象带有PubSub的借口,就可以称之为事件化对象
。
用于存储数据的对象因内容变化而发布事件时,这里用于存储数据的对象又称为Model。
MVVM,MVC中的Model。所以发布订阅模式可以用于实现MVC、MVVM模型。
(Vue双向绑定源码就用到了)
老式的javaScript靠输入事件的处理器,直接修改DOM。新式的JavaScript先改变模型,通过模型触发事件而导致DOM的更新。
事件循环与嵌套式变化
Backbone设置了两道保险,以防双向绑定,change事件无线触发。
1. 新值等于旧值,不触发change事件
2. change事件期间,不触发change事件
这里这本书举了一个关于backbone框架set/get的例子,个人觉得他讲的比较浅,但这个框架暂时有没接触到。可惜这里不是用vue双向绑定做例子讲解的。
jQuery自定义事件
自定义事件作为DOM事件冒泡技术的一个补充。
jQuery提供了非冒泡事式的triggerHandler方法。
书中举了一个进度条的例子
// 假设正在编写一个关于工具提示条的库,并希望任一时刻只能看到一个工具提示条
$('.tooltip').remove()
// 每次新建一个工具提示条的时候,先调用这个函数,删除当前的工具提示条
// 新场景,独立出某些容器,侧边栏显示新的提示条,其它地方的工具提示条不受影响,即独立出侧边栏
// $container 可以是 $('#sidebar') 或者 $(document)
$container.triggerHandler('newTootip')
$container.one('newTooltip',function(){
$tooltip.remove
})
复制代码
关于triggerHandler可参考blog.csdn.net/qq\_2285532…
当事件冒泡技术破坏我们的意图时,使用自定义事件。
小结
PubSub事件模型,难以解决一次性事件(一次性事件要求对异步函数执行的一次性任务的两种结果做不同的处理。如Ajax),这正是下一张要讲的Promise
PS:
今天读这一章的时候,还是挺开心的。特别是当自己之前阅读vue双向绑定源码,在这里的pubSub模式中,又得到了重温。有种温故知新的感觉。
但遗憾的是这本书的作者主讲的是nodejs,jquery,backbone。自己很多内容都只能看一遍,理清思路,还是有好多内容有卡壳。
不够深入,但有所收获,知道了很多概念,为知识体系添砖加瓦。
这个周末把这本书看完把,正好也把promise异步相关的内容解决掉。
继续看吧,看这些偏门书,还是很有乐趣的,你永远不知道下一章讲的你搞不搞得定。搞得定你赚了,搞不定你就亏了。不知道为什么,好象这样的体验更有趣一些,比起永远一板一眼的正确的学习。