JavaScript设计模式--桥梁模式--XHR连接队列
针对该模式的例子现在不是很理解,写下来慢慢熟悉。
们要构建一个队列,队列里存放了很多ajax请求,使用队列(queue)主要是因为要确保先加入的请求先被处理。任何时候,我们可以暂停请求、删除请求、重试请求以及支持对各个请求的订阅事件。
(1)异步请求的函数封装
/* * XHR连接对象 * 把请求的函数做成一个序列,按照执行序列来完成每一个序列项的任务 * * */ (function () { //(1)一个request请求 var asyncRequest=(function () { // function handleReadyState(o,callBack) { //设置浏览器每隔半秒执行一次函数 var poll=window.setInterval(function () { //4表示:交互完成 if(o && o.readyState==4){ //这种写法类似长连接的写法,如果不成功总是请求你(半秒请求一次) window.clearInterval(poll); if(callBack){ callBack(o); } } },500) } //(2)获取XHR的工厂 var getXHR=function () { var http; try{ http=new XMLHttpRequest(); getXHR=function () { return new XMLHttpRequest(); } }catch(e){ var msxml=[ 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'MICROSOFT.XMLHTTP' ]; for(var i=0;i<msxml.length;i++){ try { http=new ActiveXObject(msxml[i]); getXHR=function () { return new ActiveXObject(msxml[i]); }; break; }catch(e){} } } return http; } //(3)核心函数 使用返回一个单体 return function (method,url,callback,postData) { var http=getXHR(); http.open(method,url,true);//打开 handleReadyState(http,callback);//回掉连接直到成功 http.send(postData||null); } })(); //(4)为了能添加链式调用的模板 Function.prototype.method=function (name,fn) { this.prototype[name]=fn; return this; } //扩展array方法 //循环 if(!Array.prototype.forEach){ Array.method("forEach",function (fn,thisObj) { var scope=thisObj||window; for(var i=0;i<this.length;i++){//Array fn.call(scope,this[i],i,this); } }) } //过滤 if(!Array.prototype.filter){ Array.method("filter",function (fn,thisObj){ var scope=thisObj||window; var a=[]; for(var i=0;i<this.length;i++){ if(!fn.call(scope,this[i],i,this)){//??? continue; } a.push(this[i]); } }) return a; } })()
(2)建立一个简单的观察者模式
/* *一个简答简单的观察者模式 * */ (function () { //1,利用空对象来设立命名空间 window.DED= window.DED||{}; DED.util= DED.util||{}; //观察者 DED.util.Observer=function () { this.fns=[]; } //扩展方法 DED.util.Observer.prototype= { //观察 添加 subscribe: function (fn) { this.fns.push(fn); }, //取消 观察 unsubscribe: function (fn) { this.fns = this.fns.filter(function (el) { if (el != fn) { return el; } }) }, //循环执行被观察的数组 fire: function (o) { this.fns.forEach(function (el) { el(o); }) } } //序列 /* * 使用了观察者,序列可以装载任何对象,对象内容函数的调用方法不是由队列来完成,是观察者来执行的。 * */ DED.Queue=function () { //定义一个空队列 this.queue=[]; //成功观察 this.onComplete=function () {new DED.util.Observer();} //失败的观察 this.onFailure=function () {new DED.util.Observer();} //刷新观察 this.onFlush=function () {new DED.util.Observer();} //重复次数 this.retryCount=3; //当前执行次数 this.currentRetry=0; //停顿 this.paused=false; //请求超时时间 this.timeout=5000; //连接对象 this.conn={}; //计时器 this.timer={}; } //静态函数添加 DED.Queue.method("flush",function () {//刷新 if(!this.queue.length>0){ return ; } //如果是停顿状态,也不刷新 if(this.paused){ this.paused=false; return ; } var self=this; //当前连接次数+1 this.currentRetry++; var abort=function () { //可以停止一个XMLHttpRequest对象的Http请求 self.conn.abort(); if(self.currentRetry==self.retryCount){ //执行失败过的序列 self.onFailure.fire(); //重置当前次数 self.currentRetry=0; }else { self.flush(); } //计时器 this.timer=window.setTimeout(abort,this.timeout); //准备回调 var callback=function (o) { //清除定时器 window.clearTimeout(self.timer); //把当前次数清零 self.currentRetry=0; //本着先进先出的原则,把队列反序排序 self.queue.shift(); //执行队列 self.onFlush.fire(o.responseText); if(self.queue.length==0){ //如果队列等于0执行默认的成功队列 self.onComplete().fire(); return ; } self.flush();//递归 } //改变连接对象 this.conn=asyncRequest( this.queue[0]['method'], callback, this.queue[0]['parmas'] ) } }).method("setRetryCount",function (count) { this.retryCount=count; }).method("setTimeOut",function (time) { this.timer=time; }).method("add",function (o) { this.queue.push(o); }).method("pause",function () { this.paused=true; }).method("clear",function () { this.queue=[]; }).method("dequeue",function () {// this.queue.pop(); }) })()
总结
桥接模式的优点也很明显,我们只列举主要几个优点:
- 分离接口和实现部分,一个实现未必不变地绑定在一个接口上,抽象类(函数)的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现,同将抽象和实现也进行了充分的解耦,也有利于分层,从而产生更好的结构化系统。
- 提高可扩充性
- 实现细节对客户透明,可以对客户隐藏实现细节。
同时桥接模式也有自己的缺点:
大量的类将导致开发成本的增加,同时在性能方面可能也会有所减少。
As you wish.