JavaScript 是單線程、異步、非阻塞、解釋型腳本語言。JavaScript 的設計就是為了處理瀏覽器網頁的交互(DOM操作的處理、UI動畫等),決定了它是一門單線程語言。如果有多個線程,它們同時在操作 DOM,那網頁將會一團糟。
1.瀏覽器的渲染進程包含的線程
var a = 111; setTimeout(function() { console.log(222) }, 2000) fetch(url) // 假設該http請求花了3秒鍾
.then(function() { console.log(333) }) dom.onclick = function() { // 假設用戶在4秒鍾時點擊了dom
console.log(444) } console.log(555) // 結果 //555 //222 //333 //444
222,333,444在555之后被輸出,也就是說計時器setTimeout、http請求fetch、事件觸發器onclick並沒有阻塞后面的代碼。那,發生了什么?
其實,JavaScript 單線程指的是瀏覽器中負責解釋和執行 JavaScript 代碼的只有一個線程,即為 JS引擎線程,但是瀏覽器的渲染進程是提供多個線程的,如下:
- JS引擎線程(主線程)
- 事件觸發線程(onclick)
- 定時觸發器線程(setTimeout)
- 異步http請求線程(fetch)
- GUI渲染線程
- EventLoop輪詢處理線程
其中,1、2、4為常駐線程
2.消息隊列(任務隊列)
可以理解為一個靜態的隊列存儲結構,非線程,只做存儲,里面存的是一堆異步成功后的回調函數字符串,肯定是先成功的異步的回調函數在隊列的前面,后成功的在后面。
注意:是異步成功后,才把其回調函數扔進隊列中,而不是一開始就把所有異步的回調函數扔進隊列。比如setTimeout 3秒后執行一個函數,那么這個函數是在3秒后才進隊列的。
3.1中代碼的執行流程如下
步驟1:
主線程只執行了var a = 111;和console.log(555)兩行代碼,其他的代碼分別交給了其他三個線程,因為其他線程需要2、3、4秒鍾才成功並回調,所以在2秒之前,主線程一直在空閑,不斷的探查隊列是否不為空。
此時主線程里其實已經是空的了(因為執行完那兩行代碼了)
步驟2:
2秒鍾之后,setTimeout成功了