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();
    })
})()

总结

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

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

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

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

原文地址:https://www.cnblogs.com/wfaceboss/p/7679306.html