最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

異步j(luò)avascript的原理和實(shí)現(xiàn)技巧介紹

 更新時(shí)間:2012年11月08日 09:25:42   作者:  
因?yàn)楣ぷ鞯男枰乙诰W(wǎng)頁端編寫一段腳本,把數(shù)據(jù)通過網(wǎng)頁批量提交到系統(tǒng)中去。所以我就想到了Greasemonkey插件,于是就開始動(dòng)手寫,發(fā)現(xiàn)問題解決得很順利
因?yàn)楣ぷ鞯男枰?,我要在網(wǎng)頁端編寫一段腳本,把數(shù)據(jù)通過網(wǎng)頁批量提交到系統(tǒng)中去。所以我就想到了Greasemonkey插件,于是就開始動(dòng)手寫,發(fā)現(xiàn)問題解決得很順利。但是在對(duì)腳本進(jìn)行總結(jié)和整理的時(shí)候,我習(xí)慣性地問了自己一個(gè)問題:能不能再簡(jiǎn)單點(diǎn)?
我的答案當(dāng)然是“能”。

首先回顧我的數(shù)據(jù)批量提交的需求:我有一批用戶數(shù)據(jù)要插入到系統(tǒng)中,但是因?yàn)橄到y(tǒng)庫(kù)表結(jié)構(gòu)不是行列式的,所以無法轉(zhuǎn)化為sql語句插入。要插入的數(shù)據(jù)有接近200條,就是傻呵呵地手工錄入到系統(tǒng),估計(jì)也要1天的時(shí)間。作為程序員,當(dāng)然不會(huì)干這么傻的事情,我一定要用程序來解決。這個(gè)編程的過程耗費(fèi)了我1天的時(shí)間。相比手工錄入,我額外收入是這篇博文,絕對(duì)的合算!

編程平臺(tái)選擇沒花費(fèi)時(shí)間,直接選定基于Greasemonkey寫自己的腳本,瀏覽器當(dāng)然是firefox了。腳本的工作過程:
在腳本中預(yù)先存放要插入的數(shù)據(jù)
模擬鼠標(biāo)點(diǎn)擊,打開頁面中的輸入窗口
將數(shù)據(jù)錄入到輸入窗口,并模擬點(diǎn)擊“提交”按鈕,將數(shù)據(jù)提交到系統(tǒng)中。
依次循環(huán),直到所有數(shù)據(jù)都處理完畢。

這里的技術(shù)難點(diǎn)在于:
打開輸入窗口,需要等待不定期的時(shí)間,視網(wǎng)絡(luò)情況而定。
提交數(shù)據(jù)到后臺(tái),需要等待處理完畢之后才可以循環(huán)下一個(gè)數(shù)據(jù)。
如果我是菜鳥的話,我當(dāng)然直接寫一個(gè)類似這樣的應(yīng)用邏輯:
復(fù)制代碼 代碼如下:

for(var i = 0; i < dataArray.length; ++i)
{ 3: clickButtonForInputWindow();
waitInputWindow();
enterInputData(dataArray[i]);
clickSubmitButton();
waitInputWindowClose();
}

實(shí)際上這樣寫所有瀏覽器都會(huì)陷入一片白屏,并在若干分鐘之后提示“沒有響應(yīng)”而被強(qiáng)行終止掉。原因就是瀏覽器在調(diào)用javascript的時(shí)候,主界面是停止響應(yīng)的,因?yàn)閏pu交給js執(zhí)行了,沒有時(shí)間去處理界面消息。

為了滿足“不鎖死”的要求,我們可以把腳本修改成這樣:
復(fù)制代碼 代碼如下:

for(var i = 0; i < dataArray.length; ++i)
{
setTimeout(clickButtonForInputWindow);

setTimeout(waitInputWindowClose);
}

實(shí)際上setTimeout和setInterval是瀏覽器唯一可以支持異步的操作。如何更優(yōu)雅地使用這兩個(gè)函數(shù)來實(shí)現(xiàn)異步操作呢?目前簡(jiǎn)單的答案是老趙的Wind.js。雖然我沒有用過這個(gè)函數(shù)庫(kù),但是光是$await調(diào)用,就是符合我一貫對(duì)簡(jiǎn)潔的要求的。但是對(duì)于我這樣的單個(gè)文件的腳本來說,去網(wǎng)上下載一個(gè)外部js庫(kù),明顯不如有一段支持異步操作的代碼拷貝過來的快和爽。

所以我決定另辟蹊徑,做一個(gè)不要編譯而且易用性還可以更能夠Copy&Paste的異步函數(shù)庫(kù)。

說異步之前,我們一起回憶一下同步操作的幾種結(jié)構(gòu)類型:

順序:就是語句的先后順序執(zhí)行
判斷:就是判斷語句
循環(huán):嚴(yán)格來說應(yīng)該是跳轉(zhuǎn)(goto),但大多數(shù)現(xiàn)代語言都取消了goto。循環(huán)其實(shí)應(yīng)該是復(fù)合結(jié)構(gòu),是if和goto的組合體。
異步操作的難點(diǎn)在兩個(gè)地方:

異步的判斷:異步情況下的判斷基本都是檢測(cè)條件十分滿足,然后執(zhí)行某些動(dòng)作。
異步的順序:順序中的每一步操作之后都要交回控制權(quán),等待在下一個(gè)時(shí)間片中繼續(xù)執(zhí)行下一步。難點(diǎn)是如何保持順序性。尤其在兩個(gè)順序動(dòng)作中間夾雜一個(gè)異步的循環(huán)的時(shí)候。
異步的循環(huán):每次循環(huán)之后都交回控制權(quán)到瀏覽器,如此循環(huán),直到運(yùn)行結(jié)束。
最簡(jiǎn)單的實(shí)現(xiàn)當(dāng)然就是異步循環(huán)了,我的實(shí)現(xiàn)代碼如下:
復(fù)制代碼 代碼如下:

function asyncWhile(fn, interval)
{
if( fn == null || (typeof(fn) != "string" && typeof(fn) != "function") )
return;
var wrapper = function()
{
if( (typeof(fn) == "function" ? fn() : eval(fn) ) !== false )
setTimeout(wrapper, interval == null? 1: interval);
}
wrapper();
}

核心內(nèi)容就是:如果fn函數(shù)返回值不是false,就繼續(xù)下一個(gè)setTimeout的登記調(diào)用。

實(shí)際上,“等待并執(zhí)行”邏輯,根本上就是一個(gè)異步循環(huán)問題。這種情況的實(shí)現(xiàn)方法示例如下:
復(fù)制代碼 代碼如下:

asyncWhile(function(){
if( xxxCondition == false )
return true; // 表示繼續(xù)循環(huán)
else
doSomeThing();
return false; // 表示不需要繼續(xù)循環(huán)了
});

對(duì)于非等待并執(zhí)行的邏輯,簡(jiǎn)單一個(gè) setTimeout 就可以了。
異步容易,實(shí)現(xiàn)異步中的順序才叫難度呢。最早的起因是我要實(shí)現(xiàn)3步,但是第二部是一個(gè)異步的100多次的循環(huán)。也就是說,我要實(shí)現(xiàn)的3步操作,其實(shí)是103次的順序異步操作。為了一個(gè)如何在瀏覽器中實(shí)現(xiàn)可響應(yīng)的等待,找破了腦袋,只找到一個(gè)firefox中的實(shí)現(xiàn),還要申請(qǐng)?zhí)貦?quán)調(diào)用。
最后想出了一個(gè)簡(jiǎn)單的方法,就是引入了“執(zhí)行鏈(Execution Chain)”的概念,同一個(gè)執(zhí)行鏈的所有登記函數(shù)是順序的,不同執(zhí)行鏈之間沒有任何關(guān)系。另外,不提供互斥(mutex)等概念,如果要同步,自行在代碼中檢查。
在同一個(gè)執(zhí)行鏈中,保存一個(gè)執(zhí)行令牌,只有令牌和函數(shù)序號(hào)匹配,才允許執(zhí)行,這樣就保證了異步執(zhí)行的順序性。
復(fù)制代碼 代碼如下:

function asyncSeq(funcArray, chainName, abortWhenError)
{
if( typeof(funcArray) == "function" )
return asyncSeq([funcArray], chainName, abortWhenError);

if( funcArray == null || funcArray.length == 0 )
return;

if( chainName == null ) chainName = "__default_seq_chain__";
var tInfos = asyncSeq.chainInfos = asyncSeq.chainInfos || {};
var tInfo = tInfos[chainName] = tInfos[chainName] || {count : 0, currentIndex : -1, abort : false};

for(var i = 0; i < funcArray.length; ++i)
{
asyncWhile(function(item, tIndex){
return function(){
if( tInfo.abort )
return false;
if( tInfo.currentIndex < tIndex )
return true;
else if( tInfo.currentIndex == tIndex )
{
try{
item();
}
catch(e){
if( abortWhenError ) tInfo.abort = true;
}
finally{
tInfo.currentIndex ++;
}
}
else
{
if( abortWhenError ) tInfo.abort = true;
}
return false;
};
}(funcArray[i], tInfo.count ++));
}

setTimeout(function(){
if( tInfo.count > 0 && tInfo.currentIndex == -1 )
tInfo.currentIndex = 0;
},20); // 為了調(diào)試的原因,加了延遲啟動(dòng)
}

由此,一個(gè)支持Copy&Paste的異步j(luò)s函數(shù)庫(kù)就完成了。具體的使用例子如下:
復(fù)制代碼 代碼如下:

function testAsync()
{
asyncSeq([function(){println("aSyncSeq -0 ");}
, function(){println("aSyncSeq -1 ");}
, function(){println("aSyncSeq -2 ");}
, function(){println("aSyncSeq -3 ");}
, function(){println("aSyncSeq -4 ");}
, function(){println("aSyncSeq -5 ");}
, function(){println("aSyncSeq -6 ");}
, function(){println("aSyncSeq -7 ");}
, function(){println("aSyncSeq -8 ");}
, function(){println("aSyncSeq -9 ");}
, function(){println("aSyncSeq -10 ");}
, function(){println("aSyncSeq -11 ");}
, function(){println("aSyncSeq -12 ");}
, function(){println("aSyncSeq -13 ");}
, function(){println("aSyncSeq -14 ");}
, function(){println("aSyncSeq -15 ");}
, function(){println("aSyncSeq -16 ");}
, function(){println("aSyncSeq -17 ");}
, function(){println("aSyncSeq -18 ");}
, function(){println("aSyncSeq -19 ");}
, function(){println("aSyncSeq -20 ");}
, function(){println("aSyncSeq -21 ");}
, function(){println("aSyncSeq -22 ");}
, function(){println("aSyncSeq -23 ");}
, function(){println("aSyncSeq -24 ");}
, function(){println("aSyncSeq -25 ");}
, function(){println("aSyncSeq -26 ");}
, function(){println("aSyncSeq -27 ");}
, function(){println("aSyncSeq -28 ");}
, function(){println("aSyncSeq -29 ");}
]);

asyncSeq([function(){println("aSyncSeq test-chain -a0 ");}
, function(){println("aSyncSeq test-chain -a1 ");}
, function(){println("aSyncSeq test-chain -a2 ");}
, function(){println("aSyncSeq test-chain -a3 ");}
, function(){println("aSyncSeq test-chain -a4 ");}
, function(){println("aSyncSeq test-chain -a5 ");}
, function(){println("aSyncSeq test-chain -a6 ");}
, function(){println("aSyncSeq test-chain -a7 ");}
, function(){println("aSyncSeq test-chain -a8 ");}
], "test-chain");

asyncSeq([function(){println("aSyncSeq -a0 ");}
, function(){println("aSyncSeq -a1 ");}
, function(){println("aSyncSeq -a2 ");}
, function(){println("aSyncSeq -a3 ");}
, function(){println("aSyncSeq -a4 ");}
, function(){println("aSyncSeq -a5 ");}
, function(){println("aSyncSeq -a6 ");}
, function(){println("aSyncSeq -a7 ");}
, function(){println("aSyncSeq -a8 ");}
]);
}

var textArea = null;

function println(text)
{
if( textArea == null )
{
textArea = document.getElementById("text");
textArea.value = "";
}

textArea.value = textArea.value + text + "\r\n";
}

最后,要向大家說一聲抱歉,很多只想拿代碼的朋友恐怕要失望了,如果你真的不知道怎么處理這些多余的行號(hào),你可以學(xué)習(xí)一下正則表達(dá)式的替換,推薦用UltraEdit。

相關(guān)文章

  • JavaScipt選取文檔元素的方法(推薦)

    JavaScipt選取文檔元素的方法(推薦)

    下面小編就為大家?guī)硪黄狫avaScipt選取文檔元素的方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-08-08
  • 詳解js location.href和window.open的幾種用法和區(qū)別

    詳解js location.href和window.open的幾種用法和區(qū)別

    這篇文章主要介紹了詳解js location.href和window.open的幾種用法和區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • JS 組件系列之 bootstrap treegrid 組件封裝過程

    JS 組件系列之 bootstrap treegrid 組件封裝過程

    最近產(chǎn)品需要設(shè)計(jì)一套相對(duì)完整的組織架構(gòu)的解決方案,由于組織架構(gòu)涉及到層級(jí)關(guān)系,在表格里面展示層級(jí)關(guān)系,自然就要用到所謂的treegrid。下面小編通過本文給大家分享JS 組件系列之 bootstrap treegrid 組件的封裝過程,需要的朋友可以參考下
    2017-04-04
  • js圖數(shù)據(jù)結(jié)構(gòu)處理 迪杰斯特拉算法代碼實(shí)例

    js圖數(shù)據(jù)結(jié)構(gòu)處理 迪杰斯特拉算法代碼實(shí)例

    這篇文章主要介紹了js圖數(shù)據(jù)結(jié)構(gòu)處理 迪杰斯特拉算法代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • javascript程序優(yōu)化問題

    javascript程序優(yōu)化問題

    寫了幾年代碼,很少談到j(luò)avascript程序的執(zhí)行效率問題,今天就舉幾個(gè)例子看看,讓大家看看程序優(yōu)化是多么重要。 這節(jié)來看看createElement和innerHTML的表現(xiàn)??纯床顒e是多大
    2008-05-05
  • JS實(shí)現(xiàn)的檢驗(yàn)身份證格式并輸出出生日期,年齡,性別,出生地示例

    JS實(shí)現(xiàn)的檢驗(yàn)身份證格式并輸出出生日期,年齡,性別,出生地示例

    這篇文章主要介紹了JS實(shí)現(xiàn)的檢驗(yàn)身份證格式并輸出出生日期,年齡,性別,出生地,涉及javascript字符串遍歷、運(yùn)算、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下
    2019-05-05
  • js跨域的幾種解決方案

    js跨域的幾種解決方案

    本文主要介紹了js跨域的幾種解決方案,主要介紹了8種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • webpack DefinePlugin源碼入口解析

    webpack DefinePlugin源碼入口解析

    這篇文章主要為大家介紹了webpack DefinePlugin源碼入口解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 淺析JavaScrip如何實(shí)現(xiàn)優(yōu)雅地退出函數(shù)

    淺析JavaScrip如何實(shí)現(xiàn)優(yōu)雅地退出函數(shù)

    退出函數(shù)怎么寫?有人會(huì)說一個(gè)?return?就退出函數(shù)了,有這么簡(jiǎn)單嗎?這篇文章小編就來和大家詳細(xì)聊聊如何在JavaScrip中優(yōu)雅地退出函數(shù)吧
    2024-03-03
  • JavaScript實(shí)現(xiàn)拖拽盒子效果

    JavaScript實(shí)現(xiàn)拖拽盒子效果

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)拖拽盒子效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02

最新評(píng)論

遵义市| 无极县| 天津市| 介休市| 静安区| 绥滨县| 鄂州市| 扬州市| 吴堡县| 东至县| 盐源县| 马鞍山市| 湛江市| 建宁县| 卓尼县| 普定县| 内黄县| 鲁甸县| 莲花县| 文山县| 敖汉旗| 嫩江县| 岳阳县| 晋州市| 德清县| 滁州市| 阿拉善左旗| 精河县| 论坛| 浑源县| 太原市| 九龙坡区| 拉孜县| 滨海县| 富平县| 孝感市| 乐安县| 东海县| 视频| 黄龙县| 河南省|