在JavaScript中使用AOP

关于AOP的基本概念,可以参见此文

为什么我要在JavaScript中使用AOP?

在我们的系统中有两个函数,func1和func2,func2是func1代码末尾的JSONP(跨域请求)回调。这两个函数内部逻辑相对复杂,代码行数也较多。

因为func1的执行频率是10秒一次(对服务器的请求频率是10秒一次),这也就意味着这个系统的实时性要求相对较高。

在现实世界,客户端与服务器之间的网络并不能保证永远正常连接,

除了后端有DNSPOD、反向代理等容灾方案,前端也需要做一些同样的工作。

现在我需要在原有已经相对复杂的函数中加入请求超时次数统计功能,一旦发现连续超时次数到达临界点,立即切换到备用服务器。

超时统计无非就是在func1的开始设置一个变量,func2结束后还原为初始值,如果在指定的超时时间段内发现变量未还原则判定为请求超时。

这段代码与原函数func1和func2均无逻辑关联,所以尽量不直接修改这2个函数的代码,

加之func1和func2已经相对复杂,若直接修改函数内部代码将导致代码复杂度加倍而且难于维护。

此时如果能够实现一种插件机制为func1增加统计功能,而不影响原函数的逻辑,那样就完美了!

没错,这就是AOP的思想,幸好在JavaScript中实现AOP并不难。

如何实现AOP?

<html>

<body>

<script>

var _ = function(id){return document.getElementById(id);};

var GFRAME = {};

GFRAME.name = 'GFRAME';

GFRAME.func1 = function(x){

console.log(this.name,x);

}

_.inject = function(args){

var origin = args.name,

context = args.context || window,

start = args.start || (function(){}),

end = args.end || (function(){});

var temp = context[origin];

if(typeof temp != 'function')

throw Error(origin + ' is not a function in the given context.');

if(typeof start != 'function' || typeof end != 'function' )

throw Error('start and end is not a function in the given context.');

context[origin] = function(){

start.apply(this,arguments);

temp.apply(this,arguments);

end.apply(this,arguments);

};

};

_.inject({

name:'func1',

context:GFRAME,

start:function(x){

console.log('start',this.name,x);

},

end:function(x){

console.log('end',this.name,x);

}

});

GFRAME.func1('test');

</script>

输出结果:

start GFRAME test

GFRAME test

end GFRAME test

扩展阅读

我上面的实现并没有考虑原函数返回值的问题。

在微博上问了下老赵,没有想到很多人对JavaScript中的AOP还是很感兴趣。

最后周爱民大牛分享了自己的经验。很不错的一篇文章:

http://www.cnblogs.com/riceball/archive/2007/09/02/jsInject.html