前言
在日常開發中,也許我們會遇到這樣的一個問題。我們利用【釋出訂閱模式】(如果不瞭解的可以直接訪問此連結www.cnblogs.com/xiaoxiaokun… )去執行【釋出】事件時,遇到函式內部涉及到非同步執行時,就比較難以處理。為了滿足這種需求,我專門寫了一個這樣的外掛用於函式整合佇列並順序執行。
函式佇列迴圈執行
/**
*1.0.0.1版本
*/
var list=[];//儲存函式
list.push(function(){
console.log(1);
});
list.push(function(){
console.log(2);
});
list.push(function(){
console.log(3);
});
for (var i=0;fn=list[i++];) {
fn();//執行
}複製程式碼
結果:1,2,3
這是最簡單的方式,可以實現函式整合成一個佇列,按照先進先出順序執行。現在在仔細看發現,如果函式中有非同步執行那函式執行就不能保證按照順序執行,例如:
var list=[];//儲存函式
list.push(function(){
console.log(1);
});
list.push(function(){
setTimeout(function() {
console.log(2);
}, 2000);
});
list.push(function(){
console.log(3);
});
for (var i=0;fn=list[i++];) {
fn();//執行
}複製程式碼
輸出的結果肯定是 1,3,2
/**
*1.0.0.2版本
*/
var list=[];
list.push(function(){
console.log(1);
});
list.push(function(){
console.log(2);
});
list.push(function(){
console.log(3);
});
function start(list){
if(list.length){
list.shift()();
arguments.callee(list);
}
}
start(list);複製程式碼
這種方式可以等到執行完畢,清除list內部執行過後的函式。不影響下次push 執行。但是非同步函式還是未解決。
/**
*1.0.0.3版本
*/
var list=[];//儲存陣列的集合
list.push(function(){
console.log(1);
});
list.push(function(callback){
//callback是代表這個函式是非同步的函式
setTimeout(function() {
console.log(2);
callback();//執行完非同步函式執行回撥函式
}, 2000);
});
list.push(function(){
console.log(3);
});
function start(){
//判斷陣列的長度
if(list.length){
var fn=list.shift();//取出陣列第一個函式
//判斷函式是否帶有引數
if(fn.length){
fn(start);//執行該函式,並且把 start本身傳遞進去。
}else{
fn();
start();
}
}
}
start();複製程式碼
此版本可以解決帶有非同步執行的函式按照剛開始push進去的順序依次執行。
需要注意的是,如果函式是內部帶有非同步執行的函式,需要傳遞一個引數來告訴start。但是如果我們push進去的函式本身有好多個引數這需要怎麼辦呢!!接下來看另一版本。
/**
*1.0.0.4版本
*/
var list=[];//儲存陣列的集合
list.push(function(){
console.log(1);
});
list.push(function(callback){
setTimeout(function() {
console.log(2);
callback();
}, 2000);
});
list.push(function(){
console.log(3);
});
function start(){
//判斷陣列的長度
if(list.length){
var fn=list.shift();//取出陣列第一個函式
//判斷函式是否帶有引數
if(fn.length && getfunarg(fn)[0]=='callback'){
fn(start);//執行該函式,並且把 start本身傳遞進去。
}else{
fn();
start();
}
}
}
start();
/**
* 查詢函式引數名
* @fn {Function } 要查詢的函式
* @return []返回引數陣列
* */
function getfunarg(fn) {
var f = /^[\s\(]*function[^(]*\(\s*([^)]*?)\s*\)/.exec(fn.toString());
return f && f[1] ? f[1].split(/,\s*/) : [];
}複製程式碼
到現在為止,我們這幾個函式基本已經滿足我們的需求,但是push的時候,假設函式多個引數,我們還需進一步優化程式碼!為了把這個外掛做的更好。我決定還是把callback放在最後,這樣就能保證函式傳遞引數不受影響。
最終版本
/**
* 作者:小小坤
* 聯絡:java-script@qq.com
* 日期:2017-11-11
* 版本:1.0.0.4
* -----------使用說明----------
* 1、把所有函式【包含非同步執行的函式】按照順序依次 使用lk.push存入
* 2、帶有引數的函式,一定要注意{最一個引數如果是callback}會被認為是 非同步執行函式
* 3、非同步執行的函式,需要把最一個引數設定為callback。並在函式執行完畢執行callback();函式保證按照順序執行
*
* */
;! function() {
var list = [], //儲存函式的列表
isFun = Object.prototype.toString; //用於驗證是否是函式
/**
* 新增到列表中
* @fn {Function} 函式體
* */
function push(fn) {
isFun.call(fn) === "[object Function]" && list.push(fn);
};
/**
* 開始執行列表中的所有函式,
* 按照先進先出原則
*
* */
function star() {
if(list.length) {
var fn = list.shift(),//擷取第一個函式
arry=getfunarg(fn),//獲取這個函式的引數列表
_length=arry.length;//引數列表的長度
if(_length && arry[_length-1] === 'callback') {
if(_length===1){
fn(star);
}else{
arry.pop();//刪除最後一個引數
arry.push(star);//把回撥函式存入陣列
fn.apply(this,arry);
}
} else {
fn.apply(this,arry);
star();
}
}
}
/**
* 查詢函式引數名
* @fn {Function } 要查詢的函式
* @return []返回引數陣列
* */
function getfunarg(fn) {
var f = /^[\s\(]*function[^(]*\(\s*([^)]*?)\s*\)/.exec(fn.toString());
return f && f[1] ? f[1].split(/,\s*/) : [];
}
//掛在到Windows上。
window.lk = {
push: push,
start: star
}
}();
//使用測試
/**--------一條華麗的分割線--------**/
var a=100,
b=200,
d=300,
f=400;
//定義函式 a2 ,此函式帶有一個引數,被認為是非同步函式
function a2(a,b,callback) {
console.time('2');
setTimeout(function() {
console.timeEnd('2');
callback();
console.log(a,'a');
}, 1000);
}
//把函式函式 a2 放入陣列
lk.push(a2);
//定義函式 a3
function a3(d, f) {
console.log(f,'f');
console.log(3);
}
//把函式函式 a3 放入陣列
lk.push(a3);
//定義函式 a4 此函式帶有一個引數,被認為是非同步函式
function a4(callback) {
console.time('4');
setTimeout(function() {
console.timeEnd('4');
callback();
}, 2000);
}
//把函式函式 a4 放入陣列
lk.push(a4);
//最後開始執行
lk.start();複製程式碼
最終此外掛完成,需要壓縮的同學可以自行壓縮。程式碼比較簡單,提供了兩個方法。
push儲存函式列表
start開始執行
總結
通過上邊的程式碼編寫我們學到了處理函式列表時候,需要考慮到非同步函式。處理非同步函式,需要回撥函式參與。這樣就能幫助程式碼按照順序執行。