JavaScript设计模式--桥梁模式--XHR连接队列

来源:互联网 发布:使命召唤8mac版迅雷 编辑:程序博客网 时间:2024/06/06 04:49

针对该模式的例子现在不是很理解,写下来慢慢熟悉。

我们要构建一个队列,队列里存放了很多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();    })})()

总结:

桥接模式的优点也很明显,我们只列举主要几个优点:

  1. 分离接口和实现部分,一个实现未必不变地绑定在一个接口上,抽象类(函数)的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现,同将抽象和实现也进行了充分的解耦,也有利于分层,从而产生更好的结构化系统。
  2. 提高可扩充性
  3. 实现细节对客户透明,可以对客户隐藏实现细节。

同时桥接模式也有自己的缺点:

大量的类将导致开发成本的增加,同时在性能方面可能也会有所减少。