您的位置:首页 > Web前端

订阅-发布(观察者)模式在前端控件初始化时的运用

2016-10-04 18:31 573 查看
前些时候在使用公司的地址控件的时候遇到一个问题。在同一个页面,我有三处地方调用了这个地址控件。这个地址控件初始化的时候要使用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获取数据来初始化的控件中的运用。
示例地址:http://runningls.com/demos/2016/daily/ajaxOnce/
github:https://github.com/liusaint/JavaScript-record/tree/master/ajaxOnce
本文地址:http://blog.csdn.net/liusaint1992/article/details/52734675
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息