前些时候在使用公司的地址控件的时候遇到一个问题。在同一个页面,我有三处地方调用了这个地址控件。这个地址控件初始化的时候要使用AJAX从后台获取所有的地址数据下来。结果发现发起了三次对地址数据的请求。
一、原始版本:
示意代码类似这样。
function A(name){
this.name = name ;
this.init();
}
A.prototype={
init:function(name){
//在回调函数中拿到初始化的这个对象
var self = this;
//拿到数据之后的回调函数
var callback = function(data){
console.log('这是初始化的'+self.name+'的回调函数');
console.log(data);
A.data = data;
}
//判断要获取的数据是否已经获取过。没获取过则ajax获取。
if(A.data){
callback(A.data);
}else{
$.ajax({
url : 'data.json',
noLoad: true,
success: callback
});
}
}
}
可以看到这个控件里,我们做了基本的对数据是否存在的判断,这样在页面再次调用的时候不会再次请求数据。
然后我们调用两次:
//第一次调用
var a = new A('1a');
//第二次调用
var aa = new A('2a');
输出:
通过输出发现我们实现了两次实例化。并且在回调中都拿到了我们实例化的对象中的数据,从而可以对这个控件进行一些其他的操作。
但是,当我打开网络面板,发现数据请求了两次:
是init()函数里的判断没有起到作用吗?
不是,其实是因为第二次实例化控件的时候,第一个的AJAX请求的数据还没有拿到, 所以第二次实例化的时候还会走AJAX流程。
那个判断的作用体现在数据拿到之后,再次调用此控件或调用此控件里的init()方法的时候,比如我再new一个A,就不会再次请求数据了,如下图。
从上面的运行情况看。这个控件显然是不完善的。我们一次实例化多次此控件,就会发起多个AJAX请求,
如果请求的数据很大的话或网络不佳,会严重影响网页体验。并且即使某一个实例中的AJAX获取到了数据,其他的实例依然会等待自己调用的AJAX获取的数据。
二、使用订阅-发布(观察者)模式完善:
要把这个控件完善起来,我们需要实现:
1.只在第一次实例化该控件的时候调用AJAX获取数据。
2.AJAX获取到数据之后执行每一个实例中的回调函数。也就是说,要在回调函数中拿到实例对象。
在这种情况下,使用订阅-发布模式无疑是很合适的。
每次实例化这个控件的时候,就订阅一下。然后拿到数据之后一次性发布出来。
看过设计模式相关的书的想必对订阅-发布模式(观察者模式)不会陌生。像我们使用的浏览器的各种事件就属于这个模式。
可以自己写一套事件机制,也可以使用jQuery那一套事件机制。这里,我就直接使用
jQuery的事件机制了。
修改代码如下:
function A(name){
this.name = name ;
this.init();
}
A.prototype={
init:function(name){
//在回调函数中拿到初始化的这个对象
var self = this;
//拿到数据之后的回调函数
var callback = function(event,data){
console.log('这是初始化的'+self.name+'的回调函数');
console.log(data);
A.data = data;
}
//判断要获取的数据是否已经获取过。没获取过则ajax获取。
if(A.data){
callback(A.data);
}else{
if(!A.ajaxing){
this.getAjaxData();
}
//订阅
$(document).on('dataOk',callback);
}
},
getAjaxData:function(){
A.ajaxing = true;
$.ajax({
url : 'data.json',
noLoad: true,
success: function(data){
//触发我们定义的这个事件,并传递ajax获取到的数据
//发布
$(document).trigger('dataOk',[data]);
A.ajaxing = false;
}
});
}
}
//第一次调用
var a = new A('1a');
//第二次调用
var aa = new A('2a');
我们定义了一个叫做‘dataOk’的事件,在没获取到数据的情况下,每次实例化这个控件者会给这个事件绑定一个回调函数。然后当AJAX获取到结果之后,使用trigger方法触发这个'dataOk'事件,并将AJAX获取到的数据传递给这个事件的回调函数。注意这里对jQuery事件机制的使用。
输出结果:
请求次数:
功能基本实现
。
那么,本文就讲了使用发布-订阅模式在要用AJAX获取数据来初始化的控件中的运用。