在比较复杂的模块中碰到无数次多个Ajax异步请求同时请求(
不会用direct),而且往往需要在这些请求都完成后,根据所有的请求结果做一些事情,比如提交表单什么的,最初的解决方式是一个请求的回调里嵌下一个请求,勉强实现后,调试维护异常纠心,一圈一圈像个洋葱。
接着右思左想之下,写下这个简易的还算能用的队列(我随便称呼的,各位大人轻拍)。
本队列能加普通函数、Ext.Ajax.request请求、Store请求,可以任意调整顺序(其实就一数组,所以,你们懂的),可以按顺序执行,也可以无序同时执行请求,在所有请求完成后有事件可监听 (废话太多了,上代码)
执行结果截图:(含一个Ajax请求、一个Store请求、一个普通函数,实例在代码的注释中,不过异步请求自己随意建就可以了)
队列顺序执行效果:
队列无序执行效果:
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
* @homepage http://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[this.executeType+"ExecuteItem"](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[index];
},
/**
* 将普通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[index];
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[0]); //开始执行队列
},
//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);
}
}
});
//private
Ext.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
* @homepage http://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时使用的,我就不一一删除了,有些注释的内容就是例子