js下寫一個(gè)事件隊(duì)列操作函數(shù)
更新時(shí)間:2010年07月19日 00:28:09 作者:
異步操作可能會(huì)產(chǎn)生你不希望的事件觸發(fā)順序。這個(gè)問題以前也遇到過,當(dāng)時(shí)沒想太多,也就是直接多層嵌套(在ajax返回以后嵌套下一個(gè)事件)來解決。
前兩天在網(wǎng)上看到這一系列的文章《寫一個(gè)JavaScript異步調(diào)用框架1,2,3,4,5,6》。
異步操作可能會(huì)產(chǎn)生你不希望的事件觸發(fā)順序。這個(gè)問題以前也遇到過,當(dāng)時(shí)沒想太多,也就是直接多層嵌套(在ajax返回以后嵌套下一個(gè)事件)來解決。
認(rèn)真的看了一遍??吹念^昏,不得不說我可能基礎(chǔ)并不好,在大局上的掌握也不好。d反正我是覺得很難理解,也不覺得它的調(diào)用時(shí)夠方便的。
如果是這么調(diào)用:
var chain = Async.go(0);
chain
.next(function(){setTimeout("alert(1)",3000)})
.next(function(){setTimeout("alert(2)",3000)})
.next(function(){setTimeout("alert(3)",3000)});
我覺得這樣是完美的。但是實(shí)際上如果是異步調(diào)用卻是要這樣:
var chain = Async.go(0);
chain.next(function(){
var operation = new Async.Operation();
setTimeout(function(){ operation.yield("hello"); }, 3000);
return operation;
});
當(dāng)然最后一篇提到再次封裝一下,我想大致上就能解決這種不方便的調(diào)用了。
其實(shí)以前我也是有過這個(gè)念頭,就是找一個(gè)能按我的順序來觸發(fā)的類或者什么,群里問問是否有這種類的時(shí)候,別人總都回句,在onreadychange里執(zhí)行就好啦,甚至有嘲笑的!加上當(dāng)時(shí)又是初學(xué)的菜鳥也便作罷了。而現(xiàn)在雖然依舊是菜鳥,但終究飛了一段路程了。就試試按自己的理解寫一個(gè)事件隊(duì)列吧。
我總習(xí)慣看代碼說話,所以先上代碼,然后說一下思路好了:
/**
KEQueue —— Events Queue
@Author ake by 2010-04-25
http://www.cnblogs.com/akecn
@param data 事件隊(duì)列中每個(gè)事件都會(huì)將該參數(shù)作為第一個(gè)參數(shù)傳遞下去,除非通過KEQueue.status修改它的值。
@method next(Function) 下一個(gè)要執(zhí)行的事件。
@method wait(Number) 等待一定時(shí)間后執(zhí)行下一個(gè)事件。
@method sleep() 停止事件序列的執(zhí)行。
@method wake() 繼續(xù)執(zhí)行事件序列。
**/
var KEQueue = function(data) {
this.staticQueue = [];
this.asyncQueue = [];
this.status = "running";
this.result = data;
return this;
}
KEQueue.prototype = {
next:function(callback, async) {//添加一個(gè)方法
if(!!async) {
this.staticQueue.push("async");//如果是異步方法(會(huì)有延時(shí)效果的方法)就添加標(biāo)識
this.asyncQueue.push(callback);//延時(shí)方法的存放數(shù)組
}else {
this.staticQueue.push(callback);//直接觸發(fā)的方法的存放數(shù)組
}
return this;
},
wait:function(delay) {//延遲執(zhí)行序列
var self = this;
this.next(function() {//模擬添加一個(gè)延時(shí)方法
setTimeout(function() {
self.wake.call(self)
}, delay);
},true);
return this;
},
go:function() {//按事件添加的先后順序依次執(zhí)行事件
if(this.staticQueue.length == 0) return;
while(this.staticQueue.length > 0) {
if(this.status === "sleep") return;
var fun = this.staticQueue.shift();
if(typeof fun == "string" && fun == "async") {
fun = this.asyncQueue.shift();
fun(this.result);
this.sleep();
}else {
fun(this.result);
}
}
},
sleep:function() {
this.status = "sleep";
},
wake:function() {
this.status = "running";
this.go();
}
}
估計(jì)你看了代碼就已經(jīng)明白是怎么做的了,代碼也很簡單。
其實(shí)就是循環(huán)去執(zhí)行一個(gè)數(shù)組中的方法,如果數(shù)組中存放的不是function,就停止隊(duì)列的操作直到被叫醒(wake())。使用方法也比較偏向我喜歡的方式。
當(dāng)然也許我只是看到事件是按我添加的順序去執(zhí)行了,但有很多其他的情況或者原因沒想到。如果您有建議或者意見,歡迎留言!
以下是使用示例。
//示例1 添加事件、執(zhí)行事件隊(duì)列
function show(n) {
console.log(n);
}
var o = new KEQueue("0");
o.next(function(d) { //參數(shù)是構(gòu)造時(shí)傳遞的數(shù)據(jù)。整個(gè)事件隊(duì)列都會(huì)返回該數(shù)據(jù)作為參數(shù)。
show(d + 1);
}).next(function(d) {
setTimeout(function() { //模擬延時(shí)操作(異步操作)
show(d + 2);
o.result = 0; //更改用以傳遞的數(shù)據(jù),如果不修改,該數(shù)據(jù)會(huì)保持一致一直傳遞到最后一個(gè)事件。
o.wake(); //需要手動(dòng)喚醒序列
},2000);
},true).next(function(d){
show(d + 3);
}).go();
o.next(function(d) {
setTimeout(function() {show(d + 4);o.wake(); },1000);
},true).wait(1000) //手動(dòng)推遲1秒執(zhí)行下面的方法
.next(function(d) {
show(d + 5);
}).go();
//示例2
o.next(function() {
show(1);
})
setTimeout(function() {
o.next(function(){
setTimeout(function() {
show(2);
o.wake();
},2000)
},true).go();
},1000);
setTimeout(function() {
o.next(function() {
show(3);
}).go();
},2000);
PS:晚上睡覺的時(shí)候突然想說如果添加的是一個(gè)復(fù)雜事件,那么所消耗的時(shí)間久長了,這樣會(huì)不會(huì)造成不期望的事件順序呢?如果這樣每個(gè)事件最后都要顯示當(dāng)做異步事件去處理,那這個(gè)隊(duì)列就沒什么大的意義了,最多就是幫你梳理一下事件順序,僅此而已了。。
早上去公司路上又突然想起,JavaScript是單線程操作的哎,事件會(huì)被阻塞的,如果是多線程,估計(jì)也不需要做這么個(gè)隊(duì)列了。
剛才寫個(gè)demo試了一下恩,看來還是沒問題的。
異步操作可能會(huì)產(chǎn)生你不希望的事件觸發(fā)順序。這個(gè)問題以前也遇到過,當(dāng)時(shí)沒想太多,也就是直接多層嵌套(在ajax返回以后嵌套下一個(gè)事件)來解決。
認(rèn)真的看了一遍??吹念^昏,不得不說我可能基礎(chǔ)并不好,在大局上的掌握也不好。d反正我是覺得很難理解,也不覺得它的調(diào)用時(shí)夠方便的。
如果是這么調(diào)用:
var chain = Async.go(0);
chain
.next(function(){setTimeout("alert(1)",3000)})
.next(function(){setTimeout("alert(2)",3000)})
.next(function(){setTimeout("alert(3)",3000)});
我覺得這樣是完美的。但是實(shí)際上如果是異步調(diào)用卻是要這樣:
var chain = Async.go(0);
chain.next(function(){
var operation = new Async.Operation();
setTimeout(function(){ operation.yield("hello"); }, 3000);
return operation;
});
當(dāng)然最后一篇提到再次封裝一下,我想大致上就能解決這種不方便的調(diào)用了。
其實(shí)以前我也是有過這個(gè)念頭,就是找一個(gè)能按我的順序來觸發(fā)的類或者什么,群里問問是否有這種類的時(shí)候,別人總都回句,在onreadychange里執(zhí)行就好啦,甚至有嘲笑的!加上當(dāng)時(shí)又是初學(xué)的菜鳥也便作罷了。而現(xiàn)在雖然依舊是菜鳥,但終究飛了一段路程了。就試試按自己的理解寫一個(gè)事件隊(duì)列吧。
我總習(xí)慣看代碼說話,所以先上代碼,然后說一下思路好了:
復(fù)制代碼 代碼如下:
/**
KEQueue —— Events Queue
@Author ake by 2010-04-25
http://www.cnblogs.com/akecn
@param data 事件隊(duì)列中每個(gè)事件都會(huì)將該參數(shù)作為第一個(gè)參數(shù)傳遞下去,除非通過KEQueue.status修改它的值。
@method next(Function) 下一個(gè)要執(zhí)行的事件。
@method wait(Number) 等待一定時(shí)間后執(zhí)行下一個(gè)事件。
@method sleep() 停止事件序列的執(zhí)行。
@method wake() 繼續(xù)執(zhí)行事件序列。
**/
var KEQueue = function(data) {
this.staticQueue = [];
this.asyncQueue = [];
this.status = "running";
this.result = data;
return this;
}
KEQueue.prototype = {
next:function(callback, async) {//添加一個(gè)方法
if(!!async) {
this.staticQueue.push("async");//如果是異步方法(會(huì)有延時(shí)效果的方法)就添加標(biāo)識
this.asyncQueue.push(callback);//延時(shí)方法的存放數(shù)組
}else {
this.staticQueue.push(callback);//直接觸發(fā)的方法的存放數(shù)組
}
return this;
},
wait:function(delay) {//延遲執(zhí)行序列
var self = this;
this.next(function() {//模擬添加一個(gè)延時(shí)方法
setTimeout(function() {
self.wake.call(self)
}, delay);
},true);
return this;
},
go:function() {//按事件添加的先后順序依次執(zhí)行事件
if(this.staticQueue.length == 0) return;
while(this.staticQueue.length > 0) {
if(this.status === "sleep") return;
var fun = this.staticQueue.shift();
if(typeof fun == "string" && fun == "async") {
fun = this.asyncQueue.shift();
fun(this.result);
this.sleep();
}else {
fun(this.result);
}
}
},
sleep:function() {
this.status = "sleep";
},
wake:function() {
this.status = "running";
this.go();
}
}
估計(jì)你看了代碼就已經(jīng)明白是怎么做的了,代碼也很簡單。
其實(shí)就是循環(huán)去執(zhí)行一個(gè)數(shù)組中的方法,如果數(shù)組中存放的不是function,就停止隊(duì)列的操作直到被叫醒(wake())。使用方法也比較偏向我喜歡的方式。
當(dāng)然也許我只是看到事件是按我添加的順序去執(zhí)行了,但有很多其他的情況或者原因沒想到。如果您有建議或者意見,歡迎留言!
以下是使用示例。
復(fù)制代碼 代碼如下:
//示例1 添加事件、執(zhí)行事件隊(duì)列
function show(n) {
console.log(n);
}
var o = new KEQueue("0");
o.next(function(d) { //參數(shù)是構(gòu)造時(shí)傳遞的數(shù)據(jù)。整個(gè)事件隊(duì)列都會(huì)返回該數(shù)據(jù)作為參數(shù)。
show(d + 1);
}).next(function(d) {
setTimeout(function() { //模擬延時(shí)操作(異步操作)
show(d + 2);
o.result = 0; //更改用以傳遞的數(shù)據(jù),如果不修改,該數(shù)據(jù)會(huì)保持一致一直傳遞到最后一個(gè)事件。
o.wake(); //需要手動(dòng)喚醒序列
},2000);
},true).next(function(d){
show(d + 3);
}).go();
o.next(function(d) {
setTimeout(function() {show(d + 4);o.wake(); },1000);
},true).wait(1000) //手動(dòng)推遲1秒執(zhí)行下面的方法
.next(function(d) {
show(d + 5);
}).go();
//示例2
o.next(function() {
show(1);
})
setTimeout(function() {
o.next(function(){
setTimeout(function() {
show(2);
o.wake();
},2000)
},true).go();
},1000);
setTimeout(function() {
o.next(function() {
show(3);
}).go();
},2000);
PS:晚上睡覺的時(shí)候突然想說如果添加的是一個(gè)復(fù)雜事件,那么所消耗的時(shí)間久長了,這樣會(huì)不會(huì)造成不期望的事件順序呢?如果這樣每個(gè)事件最后都要顯示當(dāng)做異步事件去處理,那這個(gè)隊(duì)列就沒什么大的意義了,最多就是幫你梳理一下事件順序,僅此而已了。。
早上去公司路上又突然想起,JavaScript是單線程操作的哎,事件會(huì)被阻塞的,如果是多線程,估計(jì)也不需要做這么個(gè)隊(duì)列了。
剛才寫個(gè)demo試了一下恩,看來還是沒問題的。
相關(guān)文章
移動(dòng)端如何用下拉刷新的方式實(shí)現(xiàn)上拉加載
這篇文章主要介紹了移動(dòng)端如何用下拉刷新的方式實(shí)現(xiàn)上拉加載,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12
PHPMyAdmin導(dǎo)入時(shí)提示文件大小超出PHP限制的解決方法
這篇文章主要介紹了PHPMyAdmin導(dǎo)入時(shí)提示文件大小超出PHP限制的解決方法,造成這個(gè)問題的原因是PHP上傳大小限制為2MB,修改PHP.ini配置即可解決這問題,需要的朋友可以參考下2015-03-03
JS實(shí)現(xiàn)先顯示大圖后自動(dòng)收起顯示小圖的廣告代碼
這篇文章主要介紹了JS實(shí)現(xiàn)先顯示大圖后自動(dòng)收起顯示小圖的廣告代碼,涉及javascript頁面元素屬性的操作及數(shù)學(xué)運(yùn)算技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
JS表示Stack類練習(xí)用棧實(shí)現(xiàn)任意進(jìn)制轉(zhuǎn)換
這篇文章主要為大家介紹了JS表示Stack類練習(xí)用棧實(shí)現(xiàn)任意進(jìn)制轉(zhuǎn)換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
JS中可能會(huì)常用到的一些數(shù)據(jù)處理方法
這篇文章主要給大家介紹了JS中可能會(huì)常用到的一些數(shù)據(jù)處理方法,好多知識寫下來也能加深一下自身的記憶,文中給出了詳細(xì)的實(shí)例代碼,對大家學(xué)習(xí)或者使用JS具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-09-09
js判斷手機(jī)和pc端選擇不同執(zhí)行事件的方法
這篇文章主要介紹了js判斷手機(jī)和pc端選擇不同執(zhí)行事件的方法,可實(shí)現(xiàn)判斷手機(jī)端還是PC端再選擇對應(yīng)的執(zhí)行事件的功能,是非常實(shí)用的技巧,需要的朋友可以參考下2015-01-01

