非同步javascript的原理與實作技巧介紹_javascript技巧
因為工作的需要,我要在網頁端寫一段腳本,把資料透過網頁批次提交到系統中去。所以我就想到了Greasemonkey插件,於是就開始動手寫,發現問題解決得很順利。但在對腳本進行總結和整理的時候,我習慣性地問了自己一個問題:能不能再簡單一點?
我的答案當然是「能」。
首先回顧我的資料批次提交的需求:我有一批使用者資料要插入到系統中,但是因為系統函式庫表結構不是行列式的,所以無法轉換為sql語句插入。要插入的資料有接近200條,就是傻呵呵地手工輸入到系統,估計也要1天的時間。身為程式設計師,當然不會做這麼傻的事情,我一定要用程式來解決。這個程式的過程耗費了我1天的時間。相比手工錄入,我額外收入是這篇博文,絕對的合算!
程式設計平台選擇沒花時間,直接選定基於Greasemonkey寫自己的腳本,瀏覽器當然是firefox了。腳本的工作過程:
在腳本中預先存放要插入的數據
模擬滑鼠點擊,打開頁面中的輸入窗口
將數據錄入到輸入窗口,並模擬點擊“提交”按鈕,將數據提交到系統中。
依序循環,直到所有資料都處理完畢。
這裡的技術困難在於:
開啟輸入窗口,需要等待不定期的時間,視網路情況而定。
提交資料到後台,需要等待處理完畢之後才可以循環下一個資料。
如果我是菜鳥的話,我當然直接寫一個類似這樣的應用邏輯:
for(var i = 0; i { 3: clickButtonForInputWindow();
waitInputWindow();
Input(dataArray]] ;
clickSubmitButton();
waitInputWindowClose();
}
實際上這樣寫所有瀏覽器都會陷入一片白屏,並在若干分鐘之後提示「沒有回應」而被強行終止掉。原因就是瀏覽器在呼叫javascript的時候,主介面是停止回應的,因為cpu交給js執行了,沒有時間去處理介面訊息。
為了滿足「不鎖死」的要求,我們可以把腳本修改成這樣:
複製程式碼
程式碼如下:
for(var i = 0; i {
setTimeout(clickButtonForInputWindow);
}
實際上setTimeout和setInterval是瀏覽器唯一可以支援非同步的操作。如何更優雅地使用這兩個函數來實現非同步操作呢?目前簡單的答案是老趙的Wind.js。雖然我沒有用過這個函數庫,但是光是$await調用,就是符合我一貫對簡潔的要求的。但是對於我這樣的單一檔案的腳本來說,去網上下載一個外部js庫,明顯不如有一段支援非同步操作的程式碼拷貝過來的快和爽。
所以我決定另闢蹊徑,做一個不要編譯而且易用性還可以更能夠Copy&Paste的非同步函數函式庫。
說非同步之前,我們一起回想一下同步運算的幾種結構類型:
順序:就是語句的先後順序執行
判斷:就是判斷語句
循環:嚴格來說應該是跳轉(goto),但大多數現代語言都取消了goto。循環其實應該是複合結構,是if和goto的組合。
非同步操作的困難點在兩個地方:
非同步的判斷:非同步情況下的判斷基本上都是偵測條件十分滿足,然後執行某些動作。
非同步的順序:順序中的每一步操作之後都要交回控制權,等待在下一個時間片中繼續執行下一步。難點是如何保持順序性。尤其在兩個順序動作中間夾雜一個非同步的循環的時候。
程式碼如下:
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);
}
核心內容就是:如果fn函數回傳值不是false,就繼續下一個setTimeout的登記呼叫。
實際上,「等待並執行」邏輯,根本上就是一個非同步循環問題。這種情況的實作方法範例如下:
asyncWhile(function (){
if( xxxCondition == false )
return true; // 表示繼續循環
else
doSomeThing();
return false; // 表示不需要繼續循環了
});
對於非等待並執行的邏輯,簡單一個setTimeout 就可以了。
非同步容易,實現非同步中的順序才叫難度。最早的起因是我要實現3步,但第二部是一個非同步的100多次的循環。也就是說,我要實現的3步驟操作,其實是103次的順序非同步操作。為了一個如何在瀏覽器中實現可回應的等待,找破了腦袋,只找到一個firefox中的實現,還要申請特權呼叫。
最後想出了一個簡單的方法,就是引入了「執行鏈(Execution Chain)」的概念,同一個執行鏈的所有登記函數是順序的,不同執行鏈之間沒有任何關係。另外,不提供互斥(mutex)等概念,如果要同步,請自行在程式碼中檢查。
在同一個執行鏈中,保存一個執行令牌,只有令牌和函數序號匹配,才允許執行,這樣就保證了非同步執行的順序性。
function asyncSeq(uncray, Name,funcray> {
if( typeof(funcArray) == "function" )
return asyncSeq([funcArray], chainName, abortWhenError);
if( funcArray == null || 0 )
return;
if( chainName == null ) chainName = "__default_seq_chain__";
var tInfos = asyncSeq.chainInfos = asyncSeq.chainInfos 4q}; tInfos[chainName] = tInfos[chainName] || {count : 0, currentIndex : -1, abort : false};
for(var i = 0; i for(var i = 0; i {
asyncWhile(function(item, tIndex){
return function(){
if( tInfo.abort )
return false;
if( tInfo.currentIndex else if( tInfo.currentIndex == tIndex )
{
try{
item();
}
catch(e){
if(abortWhenf ) tInfo.abort = true;
}
finally{
tInfo.currentIndex ;
}
}
else
{
if( abortWhenErrort = tInfotWhenError ). true;
}
return false;
};
}(funcArray[i], tInfo.count ));
}
setTimeout(function(){
if( tInfo.count > 0 && tInfo.currentIndex == -1 )
tInfo.currentIndex = 0;
},20); // 為了除錯的原因,加上了延遲啟動
}
由此,一個支援Copy&Paste的非同步js函式庫就完成了。具體的使用範例如下:
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 測試鏈-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 ");}
], "測試鏈」);
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; (print; 🎜>{
if( textArea == null )
{
textArea = document.getElementById("text");
textArea.value = "";
}
textArea.value = textArea.value text "rn";
}

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

華為手機如何實現雙微信登入?隨著社群媒體的興起,微信已成為人們日常生活中不可或缺的溝通工具之一。然而,許多人可能會遇到一個問題:在同一部手機上同時登入多個微信帳號。對於華為手機用戶來說,實現雙微信登入並不困難,本文將介紹華為手機如何實現雙微信登入的方法。首先,華為手機自帶的EMUI系統提供了一個很方便的功能-應用程式雙開。透過應用程式雙開功能,用戶可以在手機上同

nohup的作用及原理解析在Unix和類Unix作業系統中,nohup是一個常用的命令,用於在後台運行命令,即便用戶退出當前會話或關閉終端窗口,命令仍然能夠繼續執行。在本文中,我們將詳細解析nohup指令的作用和原理。一、nohup的作用後台運行命令:透過nohup命令,我們可以讓需要長時間運行的命令在後台持續執行,而不受用戶退出終端會話的影響。這在需要運行

程式語言PHP是一種用於Web開發的強大工具,能夠支援多種不同的程式設計邏輯和演算法。其中,實作斐波那契數列是一個常見且經典的程式設計問題。在這篇文章中,將介紹如何使用PHP程式語言來實作斐波那契數列的方法,並附上具體的程式碼範例。斐波那契數列是一個數學上的序列,其定義如下:數列的第一個和第二個元素為1,從第三個元素開始,每個元素的值等於前兩個元素的和。數列的前幾元

如何在華為手機上實現微信分身功能隨著社群軟體的普及和人們對隱私安全的日益重視,微信分身功能逐漸成為人們關注的焦點。微信分身功能可以幫助使用者在同一台手機上同時登入多個微信帳號,方便管理和使用。在華為手機上實現微信分身功能並不困難,只需要按照以下步驟操作即可。第一步:確保手機系統版本和微信版本符合要求首先,確保你的華為手機系統版本已更新至最新版本,以及微信App

在現今的軟體開發領域中,Golang(Go語言)作為一種高效、簡潔、並發性強的程式語言,越來越受到開發者的青睞。其豐富的標準庫和高效的並發特性使它成為遊戲開發領域的一個備受關注的選擇。本文將探討如何利用Golang來實現遊戲開發,並透過具體的程式碼範例來展示其強大的可能性。 1.Golang在遊戲開發中的優勢作為靜態類型語言,Golang正在建構大型遊戲系統

PHP遊戲需求實現指南隨著網路的普及和發展,網頁遊戲的市場也越來越火爆。許多開發者希望利用PHP語言來開發自己的網頁遊戲,而實現遊戲需求是其中一個關鍵步驟。本文將介紹如何利用PHP語言來實現常見的遊戲需求,並提供具體的程式碼範例。 1.創造遊戲角色在網頁遊戲中,遊戲角色是非常重要的元素。我們需要定義遊戲角色的屬性,例如姓名、等級、經驗值等,並提供方法來操作這些

並發和非同步編程並發編程處理同時執行的多個任務,非同步編程是一種並發編程,其中任務不會阻塞線程。 asyncio是python中用於非同步程式設計的函式庫,它允許程式在不阻塞主執行緒的情況下執行I/O操作。事件循環asyncio的核心是事件循環,它監控I/O事件並調度相應的任務。當一個協程準備好時,事件循環會執行它,直到它等待I/O操作。然後,它會暫停協程並繼續執行其他協程。協程協程是可暫停和恢復執行的函數。 asyncdef關鍵字用於建立協程。協程使用await關鍵字等待I/O作業完成。 asyncio的基礎以下

目錄Astar Dapp 質押原理質押收益 拆解潛在空投項目:AlgemNeurolancheHealthreeAstar Degens DAOVeryLongSwap 質押策略 & 操作“AstarDapp質押”今年初已升級至V3版本,對質押收益規則做了不少調整。目前首個質押週期已結束,第二質押週期的「投票」子週期剛開始。若要獲得「額外獎勵」收益,需掌握此關鍵階段(預計持續至6月26日,現餘不到5天)。我將細緻拆解Astar質押收益,
