setTimeout、setInterval的使用
Javascript api文件中定義setTimeout和setInterval第二個參數意義分別為間隔多少毫秒後回呼函數被執行和每隔多少毫秒回呼函數被執行。但隨著工作經驗的積累,我們發現事實並非如此。
例如
div.onclick=function(){ setTimeout(function(){ document.getElementById('input').focus(); },0); }
就解釋不通了,立即執行就立即執行唄,幹嘛還要設置個定時兜個圈子呢。
又有一天你寫了下面一段程式碼
setTimeout(function(){while(true){}},100); setTimeout(function(){alert('你好');},200);
第一行程式碼死循環,結果造成第二行alert總是沒有出現,為啥哩?
單線程or多線程?
原來,Javascript引擎是單執行緒運行的,瀏覽器只有一個執行緒在執行JavaScript程式。因為單執行緒的設計,所以免去了複雜的多執行緒同步問題。
當設定一個定時的時候,瀏覽器會在設定的時間後將你指定的回呼函數插入任務序列,而非立即執行。如果設定定時時間為0,表示立即插入任務序列,而不是立即執行,仍然要等隊列中任務執行完畢,輪到你,你才執行。
所以下面程式碼先彈出2,再彈出1
setTimeout(function(){ alert(1); },0); alert(2);
那麼,這又有什麼實際用途呢?且看下面範例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>setTimeout 0</title> </head> <body> 输入字符,但内容却不能实时显示<input type="text" onkeydown="show(this.value)"/> <br/> 输入字符,内容能实时显示<input type="text" onkeydown="var self=this;setTimeout(function(){show(self.value)},0)"/> <div></div> <script> function show(val){ document.getElementsByTagName("div")[0].innerHTML=val; } </script> </body> </html>
這個範例中,js引擎需要執行keydown事件處理程序,然後更新輸入框的value值。事件處理程序執行時,更新value的任務只能進入佇列等待,所以keydown事件執行時無法得到更新後的value值;但透過setTimeout我們把取value的操作放入佇列,並在更新value之後執行,所以內容就能即時顯示了。
再回來看看下面的程式碼:
setTimeout(function(){ //do something... setTimeout(arguments.callee,10); },10); setInterval(function(){ //do something... },10);
這兩段程式碼看起來效果一樣,是不是。其實還是有差別的,第一段的回呼函數內的setTimeout是js引擎執行後再設定的新的定時,假定從上一個回調處理完到下一個回調開始為一個時間間隔,理論上時間間隔> =10ms,後一段代碼
說到這兒,那XMLHttpRequest是不是真的非同步呢?是的,請求是異步的,不過這請求是瀏覽器新開的一個執行緒。當請求的狀態變更時,如果先前已設定回調,非同步執行緒就將狀態變更事件放入js引擎處理佇列中等待處理,當任務被處理時js引擎總是單執行緒地執行onreadystatechange所設定的函數的。
以上所述就是本文的全部內容了,希望大家能夠喜歡。