由 John Resig 的 How JavaScript Timers Work 可以知道,現有的 JavaScript 引擎是單線程處理任務的。它把任務放到隊列中,不會同步去執行,必須在完成一個任務后才開始另外一個任務。
讓我們看看我之前的文章:JavaScript的9個陷阱及評點,在第 9 點 Focus Pocus 中提到的問題。原作者對這個認識有所偏差,其實不只是 IE 的問題,而是現有 JavaScript 引擎對於線程實現的問題(關於線程,我的概念其實不多,如果不對,希望讀者多多指教)。我們通過一個例子來說明,請訪問http://realazy.org/lab/settimeout.html. 我們來看 1 和 2。如果你能看看源代碼,會發現我們的任務很簡單,就是給文檔增加一個 input 文本框,並聚焦和選中。請現在分別點擊一下,可以看到,1 並沒有能夠聚焦和選中,而 2 可以。它們之間的區別在於,在執行:
input.focus();
input.select();
時, 2 多了一個延遲時間為 0 的 setTimeout 的外圍函數,即:
setTimeout(function(){
input.focus();
input.select();
}, 0);
按照 JavaScript: The Definitive Guide 5th 的 14.1 所說:
在實踐中,setTimeout 會在其完成當前任何延宕事件的事件處理器的執行,以及完成文檔當前狀態更新后,告訴瀏覽器去啟用 setTimeout 內注冊的函數。
其實,這是一個把需要執行的任務從隊列中跳脫的技巧。回到前面的例子,JavaScript 引擎在執行 onkeypress 時,由於沒有多線程的同步執行,不可能同時去處理剛創建元素的 focus 和 select 事件,由於這兩個事件都不在隊列中,在完成 onkeypress 后,JavaScript 引擎已經丟棄了這兩個事件,正如你看到的例子 1 的情況。而在例子 2 中,由於setTimeout可以把任務從某個隊列中跳脫成為新隊列,因而能夠得到期望的結果。
這才是延遲事件為 0 的setTimeout的真正目的。在此,你可以看看例子 3,它的任務是實時更新輸入的文本,現在請試試,你會發現預覽區域總是落后一拍,比如你輸 a, 預覽區並沒有出現 a, 在緊接輸入 b 時, a 才不慌不忙地出現。其實我們是有辦法讓預覽區跟輸入框同步地,在此我沒有給出答案,因為上面所說的,就是解決思路,try it yourself!
-----------------------------------------------------------------------------------------------------------------------------------
相信所有做前端開發的同學都會經常使用 setTimeout(0) 來做很多事情,這個一度成為解決了很多前端疑難雜症的法寶。而且大家也知道 setTImeout(0) 的極限在16ms左右。也許很多人沒想到這個是一個很嚴重的問題,但是在w3c性能小組的專家眼里這是一個非常糾結的設置。
那setTimeout和16ms會帶來什么問題呢?
1. 我們都知道,我們在做頁面動畫的時候大多數都是在用setTImeout來控制每一幀的動畫的, 而多個setTimeout的存在會導致很多次CPU中斷調度的開銷,為了減少這些開銷,我們希望同一個統一的CPU中斷調度管理調度單元來管理所有動畫,
於是就出現了 requestAnimationFrame。 requestAnimationFrame 的出現不僅僅可以解決中斷調度的問題,還可以更加優化得統一管理動畫單元里dom元素的repaint方式。
2. 杯具的16ms,在早期。js的callback執行,是依賴CPU的中斷來進行控制的,如果兩個中斷之間時間太短會導致,CPU性能消耗很高,同時影響能耗,於是微軟和英特公司為了解決這個問題,就約定每個中斷之間的間隔是15.6ms(64 fps)所以就是我們常見的約等於16ms的間隔。不過隨着web的要求不斷增加,大家對這個要求希望是放寬的態度,於是在高端瀏覽器,這個性能被提升了4倍左右,所以在chrome,ie10等瀏覽器,setTimeout的間隔縮短到了 4ms (250 fps)。 但是問題來了,這么高的消耗以傳統的方式,並不能從根本上解決CPU的調度問題,而且能耗也會提升40%
於是W3C,提出需要取代 setTimeout(0) 的代替品 --- setImmediate
不過到底底層如何解決了這個CPU調度,還能保證腳本能夠很快執行,這塊舜子還在研究,了解的朋友也歡迎一起交流哈。
這是兩個非常好的方法用來取代setTimeout的api,舜子也做了一些小小的實驗來驗證 requestAnimationFrame,setImmediate 和 setTimeout 之間的執行效率區別,在IE10下可以看到,setImmediate 接口的callback次數可以達到每秒 6000 次的的執行。而requestAnimationFrame主要目的是為了保證動畫的圓滑播放,所以基本上是控制在60 fps的范圍,而且根據文檔介紹,只是一個時鍾控制器在進行調度,而且會更加需要來進行按需渲染。
http://www.pjhome.net/web/html5/timing_test.htm
轉自:http://www.pjhome.net/article/Javascript/setImmediate_requestAnimationFrame.html
--------------------------------------------------------------------------------------------------------------------------------------
body { background:url(images/page-bg.gif); font-size:14px;}
setTimeout為0的應用
在下面兩個輸入框里輸入字符,看看有什么不同?
A:沒有使用setTimeout
B:setTimeout為0
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< meta http-equiv ="Content-Type" content ="text/html; charset=gb2312" />
< title > setTimeout為0的應用 </ title >
< style type ="text/css" >
body { background : url(images/page-bg.gif) ; font-size : 14px ; }
</ style >
</ head >
< body >
< h1 > setTimeout為0的應用 </ h1 >
< p > 在下面兩個輸入框里輸入字符,看看有什么不同? </ p >
< p >
A: < input type ="text" id ="t1" name ="t1"
onkeydown ="document.getElementById('t1text').innerHTML='你輸入了:'+this.value;" value ="" /> 沒有使用setTimeout
</ P >
< div id ="t1text" > 你輸入了: </ div >
< p >
B: < input type ="text" id ="t2" name ="t2"
onkeydown ="var t2=this;setTimeout(function(){document.getElementById('t2text').innerHTML='你輸入了:'+t2.value},0);"
value ="" /> setTimeout為0 </ p >
< div id ="t2text" > 你輸入了: </ div >
</ body >
</ html >
小結:
類似起線程。前者沒用settimeout ,所以是主線程去做的響應,所以在onkeydown 就觸發事件執行。得到的數據會有差異。
-------------------------------------------------------------------------------------------------------------------------------------------
經常看到setTimeout延時0ms的javascript代碼,感到很迷惑,難道延時0ms和不延時不是一個道理嗎?后來通過查資料以及實驗得出以下兩個作用,可能還有作用我還不知道,希望得知的朋友在后面評論上不吝指出。
1、實現javascript的異步;
正常情況下javascript都是按照順序執行的。但是我們可能讓該語句后面的語句執行完再執行本身,這時就可以用到setTimeout延時0ms來實現了。
如:
alert(1);
setTimeout("alert(2)", 0);
alert(3);
雖然延時了0ms,但是執行順序為:1,3,2
這樣就保證setTimeout里面的語句在某一代碼段中最后執行。
2、在事件中,setTimeout 會在其完成當前任何延宕事件的事件處理器的執行,以及完成文檔當前狀態更新后,告訴瀏覽器去啟用 setTimeout 內注冊的函數。;
舉個例子來說這句話的意思,假如當某個事件在頁面上建立一個文本框,並給文本框賦值(完成文檔當前狀態更新),然后將焦點定到文本框,並且選中文本框的內容(后面部分就需要用到setTimeout 延遲0ms實現,否則不好實現)。
先看個例子:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

運行示例
現有的 JavaScript 引擎是單線程處理任務的。它把任務放到隊列中,不會同步去執行,必須在完成一個任務后才開始另外一個任務。其實,這是一個把需要執行的任務從隊列中跳脫的技巧。在DEMO1中,JavaScript 引擎在執行 onmousedown時,由於沒有多線程的同步執行,不可能同時去處理剛創建元素的 focus 和 select 方法,由於這兩個方法都不在隊列中,在完成 onmousedown 后,JavaScript 引擎已經丟棄了這兩個任務,正如第一種情況。而在第二種情況中,由於setTimeout可以把任務從某個隊列中跳脫成為新隊列,因而能夠得到期望的結果。
轉自:http://www.cnblogs.com/xieex/archive/2008/07/11/1241137.html
另:
http://stackoverflow.com/questions/4574940/settimeout-with-zero-delay-used-often-in-web-pages-why
http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful