線程這個特性對於一門語言環境來講是尤爲重要的,在Java/C++環境下都提供了多線程API操做。html
但在Javascript中聽說代碼執行時單線程的,大量計算的邏輯會阻塞瀏覽器HTML渲染,但setTimeout延時處理、XHR的異步請求是如何實現的,瀏覽器
接下來咱們將逐一分析。多線程
首先須要確定的是瀏覽器中Javascript確實是單線程執行的,不信咱們能夠看個例子。異步
<html> <head></head> <body> <script> setTimeout(function(){ alert(1); },0) while(true){ //TODO } </script> </body> </html>
上面的例子中,while執行後,網頁將永遠沒法呈現。並且setTimeout內的回調代碼也不會執行。線程
這是爲何?從上咱們得出的結論是setTimeout並不能真正實現異步,但延時又是如何實現的。htm
這就須要分析瀏覽器與Javascript解釋引擎之間的關係。先給出結論,瀏覽器自己是多線程的,Javascript解釋引擎是單線程的。blog
先說說瀏覽器有哪些線程,能夠從其功能上分析,瀏覽器針對Javascript須要支持解釋執行、響應事件、渲染UI、下載資源等。隊列
可見,瀏覽器至少須要4個線程,咱們着重分析跟Javascript有關的3個線程,解釋器線程、交互線程、GUI線程。事件
下面咱們給出一張圖來描述三者之間的關係。ip
看完這張圖後,先來介紹幾個線程的做用。
JS解釋器線程主要負責JS代碼的解釋和執行;交互線程主要負責捕獲用戶點擊等事件,並將事件回調放入JS事件隊列;
GUI線程主要負責HTML頁面的渲染。三者之間存在必定聯繫,其中JS解釋線程與GUI線程互斥,由於在執行JS代碼時會阻塞頁面渲染,防止頁面數據不一致。
圖中還存在一個JS回調隊列,該隊列是JS引擎的核心,內部存放JS邏輯片、UI事件回調、XHR回調等。
由於JS引擎是基於事件驅動,內部維持一個循環執行的任務,持續讀取JS回調隊列中的任務,當隊列前一個執行完成後,便開始執行下一個回調任務。
理解上述幾個線程後,再回頭來看上面例子,便可理解。
當頁面開始load時,首先將<script>代碼片載入JS隊列並開始執行,當執行完setTimeout後,將產生一個callback放入JS隊列,而後執行while循環,此時循環沒法退出,
後面的setTimeout callback也沒法獲得執行。這也就是爲何頁面沒法渲染,由於GUI線程與JS解釋器線程互斥,並被阻塞。
關於瀏覽器中Javascript單線程就先分析到此,更多案例之後慢慢添加。