上個週日,介紹瞭如何使用setTimeout代替setInterval進行間歇調用,這個週日,繼續來說《JavaScript高級程序設計》這本書裏面,對於setTimeout的另外一種妙用——防止循環超時ajax
【這是鋪墊,爲故事的高潮埋下伏筆】編程
JS是單線程的,一個代碼塊裏面的代碼,只能按順序從上到下執行,因此若是中間有一塊代碼,執行起來很是耗時,就會致使下面的代碼沒法執行,出現瀏覽器假死的狀態。數組
JS的耗時操做,常見的有兩種 1.向服務器發起請求 2.對數組的循環操做 (固然,還有一種,就是把1和2合在一塊兒,叫作 在循環操做裏面向服務器發出請求,哈哈哈,實際項目裏面常常有人這麼幹)promise
解決這兩種耗時操做的思路都是同樣的——異步編程。JS的異步編程,並非多線程,由於正如上面所說的,JS是單線程的。JS的異步,直觀上的理解,就是延時和回調。瀏覽器
對於第一種耗時狀況,咱們採用的是ajax異步請求,待耗時的請求返回結果時,進行回調操做。服務器
對於第二種耗時狀況,則能夠使用本文即將介紹的方法,setTimeout延時調用,進行數組分塊處理。多線程
【這纔是高潮】異步
假設咱們要處理一個大小爲100的數組,對於數組中每一個元素,都須要執行大量的處理,每一個元素大約須要1s的處理時間;異步編程
而且咱們認爲,程序後面的代碼,不會依賴於咱們對這個數組的處理結果。優化
因而就有了下面這段代碼,以兩種方式來處理這個數組,一種是常規方式,一種是setTImeout的數組分塊處理
var processTime = 0; //常規操做
tcCircle(); //註釋上面的代碼 放開下面註釋 以執行setTimeout數組分塊操做 //tcCircleUseSetTimeout();
//time consuming circle
function tcCircle(){ var arr = new Array(100); for(var i=0;i<arr.length;i++){ process(arr[i]); } //頁面標題欄一直轉圈 且下面的語句遲遲沒法執行
console.log("important process"); console.log("finish!"); } function tcCircleUseSetTimeout(){ var arr = new Array(100); setTimeout(function(){ var ele = arr.shift(); process(ele); if(arr.length>0){ setTimeout(arguments.callee,100); } },100); console.log("important process"); console.log("finish!"); } function process(ele){ console.log("process"+(++processTime)); //模擬長時間的處理過程
sleep(1000); } function sleep(sleepTime){ var start=new Date().getTime(); while(true){ if(new Date().getTime()-start>sleepTime){ break; } } }
首先咱們執行常規的操做,因爲是單線程,可想而知,執行完這段程序,至少要 1*100 = 100s,而且瀏覽器會出現假死
而後咱們執行setTimeout方式的方法,setTImeout的方式,咱們每次只操做數組裏面的一個對象,而且在每次操做之間,設置了100ms的延時,供js引擎執行主幹的代碼,所以,很明顯,執行的效果很是棒!
咱們看到,不只瀏覽器的標題欄不會轉菊花了,控制檯也很快就打印出 咱們在代碼最後面打印的語句,說明主幹程序已經走完,數組的處理則定時執行着。
經過這樣的優化,咱們的程序給用戶的體驗提示了許多,固然,這裏只是書中介紹的一種方法,我相信還有不少其餘實現方式,好比我如今能夠想到的就有promise,有機會我會補充一下,你們也能夠暢所欲言,看看有什麼其餘更好的方法來對付這種循環耗時操做!