tipx 发表于 2013-1-29 10:51:13

队列执行 Ajax请求、Store请求、普通函数

http://www.agoit.com/images/smiles/icon_cry.gif 在比较复杂的模块中碰到无数次多个Ajax异步请求同时请求(http://www.agoit.com/images/smiles/icon_lol.gif 不会用direct),而且往往需要在这些请求都完成后,根据所有的请求结果做一些事情,比如提交表单什么的,最初的解决方式是一个请求的回调里嵌下一个请求,勉强实现后,调试维护异常纠心,一圈一圈像个洋葱。
http://www.agoit.com/images/smiles/icon_lol.gif 接着右思左想之下,写下这个简易的还算能用的队列(我随便称呼的,各位大人轻拍)。
http://www.agoit.com/images/smiles/icon_wink.gif 本队列能加普通函数、Ext.Ajax.request请求、Store请求,可以任意调整顺序(其实就一数组,所以,你们懂的),可以按顺序执行,也可以无序同时执行请求,在所有请求完成后有事件可监听(废话太多了,上代码)


执行结果截图:(含一个Ajax请求、一个Store请求、一个普通函数,实例在代码的注释中,不过异步请求自己随意建就可以了)

队列顺序执行效果:
http://dl.iteye.com/upload/attachment/463606/61b333bc-435e-3b84-b935-01a9f21b2f1b.jpg

队列无序执行效果:
http://dl.iteye.com/upload/attachment/463608/a2d73e34-ef9f-3db8-920d-3fcb2821dba3.jpg



Ext.ns("Ext.ux.queue");/** * @class Ext.ux.queue.Queue * @extends Ext.util.Observable * * 队列,支持Ajax,Store,普通Function * <pre><code>var log=[];var queue = new Ext.ux.queue.Queue({    listeners:{      beforequeue: function(){            //Q.info("开始执行队列------------<br/>");            //return false;      },      afterqueue: function(self, flag){            Q.info("完成---"+log.join("<br/>")+"<br/>"+flag);      }    }});//-----------------------------------Ajax队列项---------------------------------//1.直接使用【Ajax参数】方式创建Ajax队列项var q1 = queue.addAjax({    url: path+"/sys/BusiUser^checkDiscountAuthorize.action",    params:{authorizeUser: "smallBeautiful@4304", authorizePwd: "123000"},    success: function(response){      var json = Ext.decode(response.responseText);      if(false === json.success){            log.push("执行【授权success】!---false");            return false;      }      log.push("执行【授权success】!---true");      //return true;    },    failure: function(response){      log.push("执行【授权failure】!----false");      return false;    },    callback: function(){      log.push("执行【授权callback】!");      //return true;    }});//2.直接【完整参数】方式创建Ajax队列项var q1 = queue.addAjax({    params: {      url: path+"/sys/BusiUser^checkDiscountAuthorize.action",      params:{authorizeUser: "smallBeautiful@4304", authorizePwd: "123000"},      success: function(response){            var json = Ext.decode(response.responseText);            if(false === json.success){                log.push("执行【授权success】!---false");                return false;            }            log.push("执行【授权success】!---true");            //return true;      },      failure: function(response){            log.push("执行【授权failure】!----false");            return false;      },      callback: function(){            log.push("执行【授权callback】!");            //return true;      }    },    listeners: {      "beforeexecute": function(){            log.push("------------执行【q1 -> beforeexecute】!");      },      "afterexecute": function(){            log.push("------------执行【q1 -> afterexecute】!");      }    }});q1.on("beforeexecute", function(){    log.push("执行【q1 -> beforeexecute】!");});q1.on("afterexecute", function(){    log.push("执行【q1 -> afterexecute】!");});//-----------------------------------Ajax队列项----结束--------------------------//-----------------------------------Store队列项---------------------------------var q2 = queue.addStore({    store: grid.getStore(),    params: {      start:0,      limit:10,      callback: function(rs, options, success){            log.push("执行【store.load - callback】!");            //return success;      }    }//,//listeners: {//    "beforeexecute": function(){//      log.push("执行【q2 -> beforeexecute】!");//    },//    "afterexecute": function(){//      log.push("执行【q222222 -> afterexecute】!");//    }//}});q2.on("beforeexecute", function(){    log.push("执行【q2 -> beforeexecute】!");    //return false;});q2.on("afterexecute", function(){    log.push("执行【q2 -> afterexecute】!");});//两种移除队列方式queue.remove(q2);//queue.removeAt(0);//-----------------------------------Store队列项----结束-------------------------//-----------------------------------普通函数队列项------------------------------//1.使用【函数参数】创建函数队列项//var q3 = queue.addFn(function(){//    log.push("执行【q3 - fn】!");//    return true; //返回false,则代表当前队列项执行失败//});//2.使用【完整参数】创建函数队列项var q3 = queue.addFn({    fn: function(json){      log.push("执行【q3 - fn】!-----"+json.aaa);      return true;    },    params:{aaa: "我是函数参数"},    listeners: {      "beforeexecute": function(){            log.push("----listeners----执行【q3 -> beforeexecute】!");      },      "afterexecute": function(){            log.push("----listeners----执行【q3 -> afterexecute】!");      }    }});q3.on("beforeexecute", function(){    log.push("执行【q3 -> beforeexecute】!");});q3.on("afterexecute", function(){    log.push("执行【q3 -> afterexecute】!");});//【注】:可以在添加队列项时,设置顺序:queue.addAjax({...}, 1); //将当前添加的队列项设置为队列的第2项queue.orderExecute(); //顺序执行队列//queue.execute();    //无序执行队列 </code></pre> * @author    tipx * @homepagehttp://tipx.iteye.com * @version   0.1 * @revision$Id: Ext.ux.queue.js 5 2011-04-14 10:35:16 tipx $ * @depends Q * * @license Ext.ux.queue.Queue is licensed under the terms of * the Open Source LGPL 3.0 license.Commercial use is permitted to the extent * that the code/component(s) do NOT become part of another Open Source or Commercially * licensed development library or toolkit without explicit permission. * * <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html" * target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p> */Ext.ux.queue.Queue = Ext.extend(Ext.util.Observable, {    //items:[], //队列    //disorderCount:0,//队列完成计数器,初始设置为当前items.length(防止在请求途中有添加item),每执行一个请求该值减1,值为0时代表所有执行完毕,用于无序请求时,触发afterqueue事件    //orderCount:0, //队列执行计数器,初始为当前items.length,每执行一个请求该值减1,值为0时代表所有执行完毕    constructor: function(cfg){      this.items=[]; //队列容器      Ext.apply(this, cfg);      this.initEvents();      Ext.ux.queue.Queue.superclass.constructor.call(this, cfg);    },    //添加事件    initEvents: function(){      this.addEvents(            /**             * @event beforequeue 队列开始执行前事件<br/>若事件返回false,则终止执行队列             * @param {Ext.ux.queue.Queue} this 当前队列             */            "beforequeue",            /**             * @event afterqueue 队列开始执行完成事件             * @param {Ext.ux.queue.Queue} this 当前队列             * @param {boolean} success 队列执行结果,true为成功,false为失败             * <br/>当队列中任意一个队列项执行结果为false,则队列执行结果为false             * <br/>若当前队列为顺序执行时,某一队列项执行结果为false,则终止队列执行,队列执行结果为false             */            "afterqueue",            /**             * @event execute 任意一个队列项执行完毕             * @param {Ext.ux.queue.Queue} this 当前队列             * @param {boolean} success 队列项执行结果,true为成功,false为失败             */            "execute"      );      //监听队列项执行完毕事件      this.on("execute", function(self, success){            //Ext.ux.queue.EXECUTETYPE.DISORDER : 无序执行            //Ext.ux.queue.EXECUTETYPE.ORDER : 有序执行            this(success); //根据执行类型,执行相应的方法      });      //队列执行完成后,重置队列执行类型      this.on("afterqueue", function(){            this.executeType = null;      });    },    /**   * 获取队列长度   * @return {int} 队列长度   */    getCount: function(){      return this.items.length;    },    /**   * 根据索引获取队列项   * @param {int} index 索引   * @return {Ext.ux.queue.QueueItem} 队列项   */    getAt: function(index){      return this.items;    },    /**   * 将普通Ajax请求添加到队列   * @param {object} json 配置信息;允许直接传入Ajax请求参数   * @param {int} index (Optional) 队列索引,通过该参数可调整当前队列项所处的顺序,缺省添加到队列当前最后一位   * @return {Ext.ux.queue.QueueItem} 新添加的队列项   */    addAjax : function(json, index){      //url存在时,当前整个作为request的params      if(json.url){            json = {                params: json            };      }      json.qtype = Ext.ux.queue.QTYPE.AJAX;      return this.addItem(json, index);    },    /**   * 将Store请求添加到队列   * @param {object} json 配置信息   * @param {int} index (Optional) 队列索引,通过该参数可调整当前队列项所处的顺序,缺省添加到队列当前最后一位   * @return {Ext.ux.queue.QueueItem} 新添加的队列项   */    addStore : function(json, index){      return this.addItem(Ext.apply({            qtype: Ext.ux.queue.QTYPE.STORE      }, json), index);    },    /**   * 添加普通函数添加到队列   * @param {object/function} json 配置信息,直接传入函数则作为队列执行项   * @param {int} index (Optional) 队列索引,通过该参数可调整当前队列项所处的顺序,缺省添加到队列当前最后一位   * @return {Ext.ux.queue.QueueItem} 新添加的队列项   */    addFn: function(json, index){      //当json参数是函数时,则自动转换      if(Ext.isFunction(json)){            json = {                fn: json            };      }      json.qtype = Ext.ux.queue.QTYPE.FUNCTION;      return this.addItem(json, index);    },    /**   * 添加队列项(对象)   * @param {Ext.ux.queue.QueueItem} item 队列项对象   * @param {int} index (Optional) 队列索引,通过该参数可调整当前队列项所处的顺序,缺省添加到队列当前最后一位   * @return {Ext.ux.queue.QueueItem} 新添加的队列项   */    add: function(item, index){      this.items.splice(this.createIndex(index), 0, item);      return item;    },    //private    addItem: function(json, index){      var item = new Ext.ux.queue.QueueItem(json);      this.items.splice(this.createIndex(index), 0, item);      return item;    },    /**   * 移除队列项   * @param {Ext.ux.queue.QueueItem} item 待移除的队列项   * @return {Ext.ux.queue.QueueItem} 被移除的队列项;若未在当前队列中找到该队列项,将返回undefined   */    remove: function(item){      var index = this.items.indexOf(item);      if(index < 0){return item;}      return this.removeAt(index);    },    /**   * 按index移除队列项   * @param {int} index 待移除的队列项索引   * @return {Ext.ux.queue.QueueItem} 被移除的队列项;若未在当前队列中找到该队列项,将返回undefined   */    removeAt: function(index){      var item = this.items;      this.items.splice(index, 1);      return item;    },    //private    //根据index生成有效的index值    createIndex: function(index){      var len = this.items.length;      //不能直接使用 index = index || len; //此种方式导致index为0时,将会使用len的值      if(Ext.isEmpty(index)){            index = len;      }      index = Math.min(index, len);      return index;    },    /**   * 不限制顺序地执行队列   */    execute: function(){      if(false === this.fireEvent("beforequeue", this)){            return;      }      var items = this.items;      this.disorderState = true; //初始执行状态,当无序队列中有一个队列项执行结果为false,则队列执行结果为false      this.executeType = Ext.ux.queue.EXECUTETYPE.DISORDER; //设置执行类型      this.disorderCount = items.length; //初始化【无序队列】计数器      if(items.length < 1){            this.fireEvent("afterqueue", this, true);      }      var thiz = this;      Q.each(this.items, function(item){            thiz.executeItem(item); //执行队列      });    },    /**   * 按顺序执行队列   */    orderExecute: function(){      if(false === this.fireEvent("beforequeue", this)){            return;      }      var items = this.items;      this.executeType = Ext.ux.queue.EXECUTETYPE.ORDER; //设置执行类型      this.orderCount = 0; //初始化【有序队列】计数器      if(items.length < 1){            this.fireEvent("afterqueue", this, true);      }      this.executeItem(items); //开始执行队列    },    //private    //执行队列项    executeItem: function(item){      var thiz = this;      //队列项执行完毕事件监听      item.on("afterexecute", function(item, flag){            thiz.fireEvent("execute", this, false !== flag);      }, item, {single:true});      item.execute();    },    //private    //顺序执行队列项    orderExecuteItem: function(success){      this.orderCount++;      var item = this.getAt(this.orderCount);      if(item){            if(false === success){ //执行失败时触发队列完成事件                this.fireEvent("afterqueue", this, false);            }else{ //执行成功则继续往下执行                this.executeItem(item); //开始执行队列            }      }else{            //最后的队列项            //执行成功或失败都触发队列完成事件            this.fireEvent("afterqueue", this, false !== success);      }    },    //private    //无序执行队列项    disorderExecuteItem: function(success){      this.disorderCount--;      //当无序队列中有一个队列项执行结果为false,则队列执行结果为false      if(false === success){            this.disorderState = false;      }      //为0时,执行完毕      if(this.disorderCount == 0){            this.fireEvent("afterqueue", this, this.disorderState);      }    }});//privateExt.apply(Ext.ux.queue, {    /**   * @class Ext.ux.queue.QTYPE   * 队列项类型   */    QTYPE : {      /**         * 队列项函数类型         * 直接使用返回值来判断执行结束,触发执行完成事件,并获得执行结果         * @type Ext.ux.queue.QTYPE         * @property FUNCTION         */      FUNCTION: "Fn",      /**         * 队列项Ajax类型         * @type Ext.ux.queue.QTYPE         * @property AJAX         */      //普通ajax请求,如: Ext.Ajax.request,只需要传用于request的参数(url、params、callback等)即可      //通过添加回调函数来感知执行结束、触发执行完成事件,以及获取执行结果      AJAX: "Ajax",      /**         * 队列项Store类型         * @type Ext.ux.queue.QTYPE         * @property STORE         */      //数据源请求, 如:store.load, store.reload,需要分开传入store对象,以及参数(参数应当允许为空)      //通过添加回调函数来感知执行结束、触发执行完成事件,以及获取执行结果      STORE: "Store"    },    //执行类型    EXECUTETYPE: {      DISORDER: "disorder", //无序执行      ORDER: "order" //有序    }});/** * @class Ext.ux.queue.QueueItem * @extends Ext.util.Observable * * 队列项,支持Ajax,Store,普通Function * <pre><code>var qi = new Ext.ux.queue.QueueItem({    qtype: Ext.ux.queue.QTYPE.FUNCTION,    fn: function(json){      log.push("执行【qi - fn】!-----"+json.ccc);      return true;    },    params: {ccc: "item参数!!!"},    listeners: {      "beforeexecute": function(){            log.push("listeners----执行【qi -> beforeexecute】!");      },      "afterexecute": function(){            log.push("listeners----执行【qi -> afterexecute】!");      }    }});qi.execute(); //单独执行队列项//将队列项放入队列中执行var queue = new Ext.ux.queue.Queue();queue.add(qi);queue.execute(); </code></pre> * @author    tipx * @homepagehttp://tipx.iteye.com * @version   1 * @revision$Id: Ext.ux.queue.js 5 2011-04-14 11:06:25 tipx $ * @depends Q * * @license Ext.ux.queue.QueueItem is licensed under the terms of * the Open Source LGPL 3.0 license.Commercial use is permitted to the extent * that the code/component(s) do NOT become part of another Open Source or Commercially * licensed development library or toolkit without explicit permission. * * <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html" * target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p> */Ext.ux.queue.QueueItem = Ext.extend(Ext.util.Observable, {    constructor: function(cfg){      cfg = Ext.apply({            /**             * @cfg {function} fn 普通函数队列项中的执行函数<br/>函数执行结果为false,则事件afterexecute的success参数为false             */            //fn: undefined,            //ajax: undefined,            /**             * @cfg {Ext.data.Store} store store函数队列项时,必传属性<br/>该回调函数执行结果为false,则事件afterexecute的success参数为false             */            //store: undefined,            /**             * @cfg {object} scope 执行函数、回调函数中使用的this代表的作用域,缺省为当前队列项QueueItem             */            scope: this, //作用域,缺省为当前队列项            /**             * @cfg {Ext.ux.queue.QTYPE} qtype 队列项类型             * <br/>(缺省值)普通函数队列项:Ext.ux.queue.QTYPE.FUNCTION             * <br/>Ajax队列项:Ext.ux.queue.QTYPE.AJAX             * <br/>Store队列项:Ext.ux.queue.QTYPE.STORE             */            qtype: Ext.ux.queue.QTYPE.FUNCTION, //类型缺省为普通函数            /**             * @cfg {object} params 执行参数<br/>             * 普通函数队列项时:该参数为执行函数的参数,参数只能使用一个json格式的参数;<br/>             * Ajax队列项时:该参数为执行Ajax请求的参数;<br/>             * Store队列项时:该参数为Store.load方法的参数;<br/>             * 【注】:异步请求时,回调函数执行结果为false,则事件afterexecute的success参数为false             */            params:{} //执行参数,缺省为空      }, cfg);      Ext.apply(this, cfg);      this.initEvents();      Ext.ux.queue.QueueItem.superclass.constructor.call(this, cfg);    },    //添加事件    initEvents: function(){      this.addEvents(            /**             * @event beforeexecute 队列项执行前触发<br/>若事件返回false,则中止执行队列项             * @param {Ext.ux.queue.QueueItem} this 当前队列项             */            "beforeexecute",            /**             * @event afterexecute 队列项执行后触发             * @param {Ext.ux.queue.QueueItem} this 当前队列项             * @param {boolean} success 当前队列项执行结果,true为成功,false为失败             */            "afterexecute"      );    },    //private    //执行函数    execFn: function(){      var flag = (false !== this.fn.call(this.scope, this.params));      this.fireEvent("afterexecute", this, flag);    },    //private    //执行Ajax    execAjax: function(){      var thiz = this, scope = this.scope;      var params = Ext.ux.util.clone(this.params),            callbackFn = params.callback,            successFn = params.success,            failureFn = params.failure;      //callback不需要删除,因为会被生成的callback覆盖      delete params.success; //从参数中删除,避免重复执行      delete params.failure; //从参数中删除,避免重复执行      //将params中的回调函数统一归整到callback中      var callback = function(options, success, response){            var flag = success; //初始设置为success            //若回调函数存在,则执行它,并取出结果            if(callbackFn){                flag = callbackFn.call(scope, options, success, response);            }            //如果有successFn/failureFn,则将忽略callbackFn的执行结果            if(success){                if(successFn){                  flag = successFn.call(scope, response, options);                }            }else{                if(failureFn){                  flag = failureFn.call(scope, response, options);                }            }            //触发执行完成事件            thiz.fireEvent("afterexecute", this, flag);      }      params.callback = callback;      Ext.Ajax.request(params);    },    //private    //执行Store    execStore: function(){      var thiz = this, scope = this.scope;      var store = this.store, params = this.params, callbackFn = params.callback;      //将params中的回调函数统一归整到callback中      var callback = function(rs, options, success){            var flag = success; //初始设置为success            //若回调函数存在,则执行它,并取出结果            if(callbackFn){                flag = callbackFn.call(scope, rs, options, success);            }            //触发执行完成事件            thiz.fireEvent("afterexecute", this, flag);      }      params.callback = callback;      store.load(params);    },    /**   * 队列项执行   */    execute: function(){      if(false === this.fireEvent("beforeexecute", this)){            return;      }      //根据类型,取出相应的方法执行      this["exec"+this.qtype]();    }});


【注意】:
1.本代码虽然是一个独立的js,但引用了两个插件:Q和Ext.ux.util,直接将Q.each替换成Ext.each或自己的each方法即可以;Ext.ux.util是国外ext大牛站上下载的,见附件。
2.代码上注释巨多是在ext-doc生成API时使用的,我就不一一删除了,有些注释的内容就是例子
页: [1]
查看完整版本: 队列执行 Ajax请求、Store请求、普通函数