隊列執行 Ajax請求、Store請求、普通函數

:cry: 在比較複雜的模塊中碰到無數次多個Ajax異步請求同時請求( :lol: 不會用direct),而且往往需要在這些請求都完成後,根據所有的請求結果做一些事情,比如提交表單什麼的,最初的解決方式是一個請求的回調裏嵌下一個請求,勉強實現後,調試維護異常糾心,一圈一圈像個洋蔥。
:lol: 接着右思左想之下,寫下這個簡易的還算能用的隊列(我隨便稱呼的,各位大人輕拍)。
:wink: 本隊列能加普通函數、Ext.Ajax.request請求、Store請求,可以任意調整順序(其實就一數組,所以,你們懂的),可以按順序執行,也可以無序同時執行請求,在所有請求完成後有事件可監聽 (廢話太多了,上代碼)


執行結果截圖:(含一個Ajax請求、一個Store請求、一個普通函數,實例在代碼的註釋中,不過異步請求自己隨意建就可以了)

隊列順序執行效果:
[img]http://dl.iteye.com/upload/attachment/463606/61b333bc-435e-3b84-b935-01a9f21b2f1b.jpg[/img]

隊列無序執行效果:
[img]http://dl.iteye.com/upload/attachment/463608/a2d73e34-ef9f-3db8-920d-3fcb2821dba3.jpg[/img]


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時使用的,我就不一一刪除了,有些註釋的內容就是例子
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章