对于我来说,javascript中最有趣而又最无奈的就是事件处理了。丰富前卫的交互体验、流畅便捷的浏览操作,都需要建立在良好的事件处理机制上。然而浏览器的差异在事件处理上达到了最大化,内存泄露在事件处理函数中又最容易引入,这让很多人都对javascript的事件处理很头痛。
自定义事件就很少有这种天然的浏览器差异了。我们日常编码中接触自定义事件的机会也很多,比如一个xhr对象,一般都会定义onsuccess和onfailure等方法来处理xhr的返回结果;一个动画效果也往往会有onstart,onfinish等类似的方法来处理动画变化中的状态。由于我们一般都在编程中使用面向对象思想,很多时候代码会是这样的:
2 onSuccess:function(){},
3 onFailure:function(){},
4 onCancel:function(){}
5 });
6
7
8
9
10
11 if(xxx){
12 test.cancel()
13 }
如上,我们一般会在类里面定义好各种各样的自定义事件,然后程序会自动帮我们完成一些诸如onSuccess的函数,或者我们也可以主动调用实例的相关方法。
看似不错吧。不过如果我们有很多个这样的需求,就会有很多个这样的实例。实例多了不仅不好看,而且也很占内存。同时,这样的复用性也不见得多好。比如,我们需要很多实例,他们都用公共的一些事件处理方法,但同时又有各自的不同,我们如何实现呢?是生成多个只有细节不同的实例,还是继承一下Ajax,定义好公共方法,然后再实例化各个不同?前一种方法显得很不优雅,而后一方法则显得不是那么适合Javascript的编程,同时也会有类过多、实例过多的问题。
曾经的YUI2也是采用这样的方式。 YUI3则抛弃了OOP思想,引入了AOP思想,也就是面向切面编程,解决类似的问题。
关于AOP的解释可以看这里:http://en.wikipedia.org/wiki/Aspect-oriented_programming
通俗的讲,OOP中模型是这样:
实例.传输成功 , 实例.传输失败
而到了AOP中变成了这样:
传输.成功(实例甲) , 传输.失败(实例乙)
即,我们把一个纵向的流水关系,从中垂直劈开一个平面,由这个切面去处理各个事件。 这样,我们可以通过操作切面,达到统一切面方法的目的。各个实例各自的方法,又可以造成最后成果的区别。
我们来看看yui3中对于ajax的处理。
对于上面提到了各个实例需要的公共事件处理,我们可以这样定义:
2
3 Y.on("io:success" , function(){} , this, true );
4
5 Y.on( "io:failure" , function(){} , this );
6
7 Y.io(url);
8
9 } );
是不是很优雅,而对于特殊的事件,我们可以做如下处理:
2
3 var cfg = {
4 on: {
5 success:function(){}
6 failure:function(){}
7
8 }
9 };
10
11 Y.io(url,cfg);
12
13
14 .
15
是的,只要给Y.io传入一个新参数,定义好特殊的方法,就可以实现刚才OOP很难实现的问题了。
YUI3把AOP思想作为了一种内建的思想,除了最基础的模块外YUI3都引用了event-custom这一模块来优化代码。最近就是花了比较多的时间去研究这样一个思想。了解清楚之后,对整个YUI3的代码的了解都会有很大帮助。